aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--lib/mail.js32
-rw-r--r--lib/send.js2
-rw-r--r--lib/sockets.js2
-rw-r--r--package.json2
-rw-r--r--routes/bitcoin/send.js55
-rw-r--r--routes/invoices.js4
-rw-r--r--routes/lightning/receive.js31
-rw-r--r--routes/liquid/fee.js9
-rw-r--r--routes/liquid/receive.js8
-rw-r--r--routes/liquid/send.js34
-rw-r--r--routes/payments.js6
-rw-r--r--routes/send.js2
-rw-r--r--routes/users.js25
-rwxr-xr-xwatcher.sh20
15 files changed, 134 insertions, 101 deletions
diff --git a/.gitignore b/.gitignore
index 58f3c4fe..ab73f32c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,6 @@ lnurl-server.sqlite3
watcher.log
config
mysql
+build.json
+build.sh
+watcher.sh
diff --git a/lib/mail.js b/lib/mail.js
index 705880d2..ca2c2b81 100644
--- a/lib/mail.js
+++ b/lib/mail.js
@@ -10,6 +10,38 @@ function openInbox(cb) {
imap.openBox("INBOX", true, cb);
}
+app.post(
+ "/contact-sil",
+ ah((req, res) => {
+ const mailgun = require("mailgun-js")(config.mailgun);
+ let data = {
+ subject: "Contact form",
+ text: JSON.stringify(req.body),
+ };
+
+ mailgun.messages().send(data);
+ res.send(req.body);
+ })
+);
+
+app.post(
+ "/contact",
+ ah((req, res) => {
+ const mailgun = require("mailgun-js")(config.mailgun);
+ let data = {
+ subject: "Contact form",
+ text: JSON.stringify(req.body),
+ };
+
+ mailgun.messages().send(data);
+ res.send(req.body);
+ })
+);
+
imap.once("ready", function() {
openInbox(function(err, box) {
if (err) throw err;
diff --git a/lib/send.js b/lib/send.js
index 660fcae4..fd577231 100644
--- a/lib/send.js
+++ b/lib/send.js
@@ -6,7 +6,7 @@ send = async (amount, memo, hash, user) => {
let routingInfo = payreq.tags.find(t => t.tagName === "routing_info");
if (
routingInfo &&
- routingInfo.data.find(d => d.fee_proportional_millionths > 100)
+ routingInfo.data.find(d => d.fee_proportional_millionths > 1000)
)
throw new Error("Fee rate too high");
diff --git a/lib/sockets.js b/lib/sockets.js
index 931a9d23..bd59ee38 100644
--- a/lib/sockets.js
+++ b/lib/sockets.js
@@ -96,7 +96,7 @@ wss.on("connection", function(ws, req) {
lastSeen[token] = new Date();
try {
- if (!token || token === "null") return ws.close();
+ if (!token || token === "null" || !jwt.decode(token)) return ws.close();
const username = jwt.decode(token).username;
if (!username) throw new Error("Invalid JWT token");
diff --git a/package.json b/package.json
index d1d126bd..a62f37cf 100644
--- a/package.json
+++ b/package.json
@@ -49,7 +49,7 @@
"passport-local": "1.0.0",
"pino": "^5.17.0",
"pino-pretty": "^4.8.0",
- "pm2": "^4.5.6",
+ "pm2": "^5.1.0",
"query-string": "^6.13.1",
"sequelize": "^5.21.3",
"sqlite3": "^5.0.2",
diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js
index cab79e06..470889b3 100644
--- a/routes/bitcoin/send.js
+++ b/routes/bitcoin/send.js
@@ -1,4 +1,3 @@
-const bitcoin = require("bitcoinjs-lib");
const btc = config.liquid.btcasset;
module.exports = ah(async (req, res) => {
@@ -32,10 +31,10 @@ module.exports = ah(async (req, res) => {
total = total - change + fee;
let amount = total - fee;
- let params;
+ let account, params;
try {
await db.transaction(async transaction => {
- let account = await db.Account.findOne({
+ account = await db.Account.findOne({
where: {
id: user.account_id
},
@@ -62,38 +61,38 @@ module.exports = ah(async (req, res) => {
await account.decrement({ balance: total }, { transaction });
await account.reload({ transaction });
+ });
- params = {
- amount: -amount,
- fee,
- memo,
- account_id: account.id,
- user_id: user.id,
- rate: app.get("rates")[user.currency],
- currency: user.currency,
- address,
- confirmed: true,
- received: false,
- network: "bitcoin"
- };
+ params = {
+ amount: -amount,
+ fee,
+ memo,
+ account_id: account.id,
+ user_id: user.id,
+ rate: app.get("rates")[user.currency],
+ currency: user.currency,
+ address,
+ confirmed: true,
+ received: false,
+ network: "bitcoin"
+ };
- if (config.bitcoin.walletpass)
- await bc.walletPassphrase(config.bitcoin.walletpass, 300);
+ if (config.bitcoin.walletpass)
+ await bc.walletPassphrase(config.bitcoin.walletpass, 300);
- hex = (await bc.signRawTransactionWithWallet(hex)).hex;
- params.hash = await bc.sendRawTransaction(hex);
+ hex = (await bc.signRawTransactionWithWallet(hex)).hex;
+ params.hash = await bc.sendRawTransaction(hex);
- let payment = await db.Payment.create(params, { transaction });
+ let payment = await db.Payment.create(params);
- payment = payment.get({ plain: true });
- payment.account = account.get({ plain: true });
+ payment = payment.get({ plain: true });
+ payment.account = account.get({ plain: true });
- emit(user.username, "payment", payment);
- res.send(payment);
+ emit(user.username, "payment", payment);
+ res.send(payment);
- payments.push(params.hash);
- l.info("sent bitcoin", user.username, total);
- });
+ payments.push(params.hash);
+ l.info("sent bitcoin", user.username, total);
} catch (e) {
l.error("error sending bitcoin", e.message);
return res.status(500).send(e.message);
diff --git a/routes/invoices.js b/routes/invoices.js
index c188811e..51906b8c 100644
--- a/routes/invoices.js
+++ b/routes/invoices.js
@@ -27,6 +27,10 @@ app.post(
let { liquidAddress, invoice, user, tx } = req.body;
let { blindkey } = invoice;
+ if (invoice.amount < 0) throw new Error("amount out of range");
+ if (invoice.tip > invoice.amount || invoice.tip > 1000000 || invoice.tip < 0)
+ throw new Error("tip amount out of range");
+
if (liquidAddress) {
l.info("conversion request for", liquidAddress, invoice.text);
convert[invoice.text] = { address: liquidAddress, tx };
diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js
index 32c54de6..8d2aa750 100644
--- a/routes/lightning/receive.js
+++ b/routes/lightning/receive.js
@@ -1,20 +1,18 @@
const handlePayment = async msg => {
+ if (!msg.settled) return;
let account, total, user;
- try {
- await db.transaction(async transaction => {
- if (!msg.settled) return;
- const invoice = await db.Invoice.findOne({
- where: {
- text: msg.payment_request
- }
- });
+ const invoice = await db.Invoice.findOne({
+ where: {
+ text: msg.payment_request
+ }
+ });
- if (!invoice)
- return l.warn(
- "received lightning with no invoice",
- msg.payment_request
- );
+ if (!invoice)
+ return l.warn("received lightning with no invoice", msg.payment_request);
+
+ try {
+ await db.transaction(async transaction => {
const { text: hash, currency, memo, rate, tip, user_id } = invoice;
const amount = parseInt(msg.amt_paid_sat) - tip;
@@ -85,7 +83,12 @@ const handlePayment = async msg => {
let c = convert[msg.payment_request];
if (msg.payment_request && c) {
- l.info("lightning detected for conversion request", msg.payment_request, c.address, user.username);
+ l.info(
+ "lightning detected for conversion request",
+ msg.payment_request,
+ c.address,
+ user.username
+ );
user.account = account;
diff --git a/routes/liquid/fee.js b/routes/liquid/fee.js
index 2070873a..fad69f13 100644
--- a/routes/liquid/fee.js
+++ b/routes/liquid/fee.js
@@ -3,11 +3,6 @@ const buildTx = require("../../lib/buildliquidtx");
liquidTx = async ({ address, asset, amount, feeRate, replaceable, user }) => {
let tx, fee;
let node = lq;
- /*
- if (asset === config.liquid.btcasset) {
- node = rare;
- }
- */
if (user.account.pubkey) {
let psbt = await buildTx({
@@ -64,6 +59,8 @@ liquidTx = async ({ address, asset, amount, feeRate, replaceable, user }) => {
}
);
+ l.info("funding tx for fee estimate", tx);
+
tx = await node.fundRawTransaction(tx, params);
let blinded = await node.blindRawTransaction(tx.hex);
@@ -81,7 +78,7 @@ module.exports = ah(async (req, res) => {
let tx = await liquidTx({ ...req.body, user: req.user })
res.send(tx);
} catch (e) {
- l.error("error estimating liquid fee", e.message, e.stack);
+ l.error("error estimating liquid fee", e.message);
return res.status(500).send(e.message);
}
});
diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js
index c377a6b5..259db7c7 100644
--- a/routes/liquid/receive.js
+++ b/routes/liquid/receive.js
@@ -101,7 +101,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
user_id: user.id,
network: "liquid"
},
- order: [["id", "DESC"]],
+ order: [["id", "DESC"]]
});
if (!invoice) return;
@@ -286,9 +286,9 @@ setInterval(async () => {
for (let i = 0; i < arr.length; i++) {
const hash = arr[i];
- let account, address, user, total;
+ let account, address, user, total, p;
await db.transaction(async transaction => {
- let p = await db.Payment.findOne({
+ p = await db.Payment.findOne({
where: { hash, confirmed: 0, received: 1 },
include: [
{
@@ -347,7 +347,7 @@ setInterval(async () => {
});
let c = convert[address];
- if (address && c) {
+ if (address && c && p.account.asset === network.assetHash) {
l.info(
"liquid detected for conversion request",
address,
diff --git a/routes/liquid/send.js b/routes/liquid/send.js
index 19b7344f..13f77d26 100644
--- a/routes/liquid/send.js
+++ b/routes/liquid/send.js
@@ -1,5 +1,6 @@
const btc = config.liquid.btcasset;
const lcad = config.liquid.cadasset;
+const { Transaction } = require("liquidjs-lib");
sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
if (amount > 10000000) throw new Error("Amount too large");
@@ -48,7 +49,8 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
const assets = Object.keys(totals);
const payments = [];
- return db.transaction(async transaction => {
+ let main, signed;
+ await db.transaction(async transaction => {
for (let i = 0; i < assets.length; i++) {
let asset = assets[i];
let amount = totals[asset];
@@ -75,12 +77,12 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
await faucet.reload({ transaction });
await faucet.save({ transaction });
}
-
- total += fee - covered;
}
+
+ total += fee - covered;
}
- if (limit && total > limit)
+ if (limit && total > limit + fee)
throw new Error("Tx amount exceeds authorized amount");
if (asset !== btc || total) {
@@ -132,16 +134,11 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
}
}
- if (config.liquid.walletpass)
- await lq.walletPassphrase(config.liquid.walletpass, 300);
-
- let blinded = await lq.blindRawTransaction(tx.hex);
- let signed = await lq.signRawTransactionWithWallet(blinded);
- let txid = await lq.sendRawTransaction(signed.hex);
-
- l.info("sent liquid tx", txid, address);
+ signed = await lq.signRawTransactionWithWallet(
+ await lq.blindRawTransaction(tx.hex)
+ );
+ let txid = Transaction.fromHex(signed.hex).getId();
- let main;
for (let i = 0; i < assets.length; i++) {
p = payments[i];
if (p) {
@@ -157,15 +154,22 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => {
emit(user.username, "account", main.account);
emit(user.username, "payment", main);
- return main;
});
+
+ if (config.liquid.walletpass)
+ await lq.walletPassphrase(config.liquid.walletpass, 300);
+
+ let txid = await lq.sendRawTransaction(signed.hex);
+ l.info("sent liquid tx", txid, address);
+
+ return main;
};
module.exports = ah(async (req, res) => {
let { user } = req;
try {
- res.send(await sendLiquid({...req.body, user }));
+ res.send(await sendLiquid({ ...req.body, user }));
} catch (e) {
l.error("problem sending liquid", user.username, e.message);
return res.status(500).send(e);
diff --git a/routes/payments.js b/routes/payments.js
index a749e333..e78730d2 100644
--- a/routes/payments.js
+++ b/routes/payments.js
@@ -151,9 +151,9 @@ ah(async () => {
const { hdkeypath } = await lq.getAddressInfo(address);
const parts = hdkeypath.split("/");
app.set("lqAddressIndex", parts[parts.length - 1].slice(0, -1));
- } catch (e) {
- console.error("Problem getting liquid address", e);
- }
+ } catch(e) {
+ l.warn("Problem getting liquid address index", e.message);
+ }
}, 50);
}
diff --git a/routes/send.js b/routes/send.js
index 579e70b4..3aec9fb6 100644
--- a/routes/send.js
+++ b/routes/send.js
@@ -45,7 +45,7 @@ module.exports = ah(async (req, res, next) => {
};
if (!username) {
- return res.status(500).send("Vouchers temporarily disabled");
+ throw new Error("Vouchers temporarily disabled");
l.info("creating redeemable payment");
params.redeemcode = uuidv4();
params.hash = `${req.get("origin")}/redeem/${params.redeemcode}`;
diff --git a/routes/users.js b/routes/users.js
index 71f4b89a..23f016c7 100644
--- a/routes/users.js
+++ b/routes/users.js
@@ -148,7 +148,8 @@ app.post(
return res.status(500).send("Username taken");
} else {
sockets[username] = sockets[user.username];
- if (user.username !== username) l.info("changing username", user.username, username);
+ if (user.username !== username)
+ l.info("changing username", user.username, username);
user.username = username;
token = jwt.sign({ username }, config.jwt);
@@ -323,10 +324,7 @@ app.post(
(user.password &&
!(await bcrypt.compare(req.body.password, user.password)))
) {
- l.warn(
- "invalid username or password attempt",
- req.body.username
- );
+ l.warn("invalid username or password attempt", req.body.username);
return res.status(401).end();
}
@@ -426,11 +424,24 @@ app.get(
: config.liquid.network
];
type = "p2sh";
-
+
// async request to node to bump its internal index but don't use result
- lq.getNewAddress().catch(console.error);
+ lq.getNewAddress().catch(e =>
+ l.warn("Problem bumping liquid address index", e.message)
+ );
i = parseInt(app.get("lqAddressIndex"));
+
+ if (!i) {
+ const { hdkeypath } = await lq.getAddressInfo(
+ await lq.getNewAddress()
+ );
+ const parts = hdkeypath.split("/");
+ i = parts[parts.length - 1].slice(0, -1);
+ }
+
+ if (!i) throw new Error("Problem generating address");
+
hd = fromBase58(config.liquid.masterkey, n).derivePath(`m/0'/0'/${i}'`);
app.set("lqAddressIndex", i + 1);
} else {
diff --git a/watcher.sh b/watcher.sh
deleted file mode 100755
index 3fb60993..00000000
--- a/watcher.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-sats=100000000
-threshold=$1
-while true
-do
- ln=$(lncli --lnddir=/root/.lnda --network=mainnet --chain=bitcoin --rpcserver=localhost:10001 channelbalance | jr .balance)
- bc=$(bitcoin-cli getbalance)
- el=$(elements-cli getbalance | jr .bitcoin)
- total=$(node -pe "$ln + $bc * $sats + $el * $sats")
- low=$(node -pe "$total < $threshold")
- echo $(date -Is) ln $ln bc $bc el $el tot $total
- if "$low"; then
- echo "Threshold hit, setting new threshold"
- threshold=$total
- # yarn pm2 stop 0 > /dev/null
- node /root/mailgun/index.js
- fi
- sleep 10
-done