aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2020-04-29 20:59:05 -0700
committerAdam Soltys <[email protected]>2020-04-29 21:03:33 -0700
commitfa84d5a65844602c7e97e9bf0e5a51befdebaf53 (patch)
tree3e0335eea275a5de9040eb3cc6dfc62c6e190575
parent001c0291ad6eabe5684138422adfa0e851d507a6 (diff)
downloadcoinos-server-fa84d5a65844602c7e97e9bf0e5a51befdebaf53.tar.gz
coinos-server-fa84d5a65844602c7e97e9bf0e5a51befdebaf53.zip
update account balance properly after lightning payment
-rw-r--r--db/models/payments.js9
-rw-r--r--lib/utils.js48
-rw-r--r--routes/bitcoin/receive.js12
-rw-r--r--routes/bitcoin/send.js4
-rw-r--r--routes/lightning/receive.js3
-rw-r--r--routes/lightning/send.js127
6 files changed, 119 insertions, 84 deletions
diff --git a/db/models/payments.js b/db/models/payments.js
index 8c464293..076a644f 100644
--- a/db/models/payments.js
+++ b/db/models/payments.js
@@ -64,6 +64,15 @@ const attributes = {
comment: null,
field: "rate"
},
+ preimage: {
+ type: DataTypes.STRING(255),
+ allowNull: true,
+ defaultValue: null,
+ primaryKey: false,
+ autoIncrement: false,
+ comment: null,
+ field: "preimage"
+ },
network: {
type: DataTypes.STRING(255),
allowNull: true,
diff --git a/lib/utils.js b/lib/utils.js
index a861f8b7..cd1b3d69 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -1,8 +1,8 @@
const sequelize = require("sequelize");
const { Op } = sequelize;
-getUser = async username => {
- let user = await db.User.findOne({
+getUser = async (username, transaction) => {
+ let params = {
include: [
{
model: db.Account,
@@ -14,11 +14,18 @@ getUser = async username => {
}
],
where: { username }
- });
+ };
+
+ if (transaction) {
+ params.lock = transaction.LOCK.UPDATE;
+ params.transaction = transaction;
+ }
+
+ let user = await db.User.findOne(params);
user = user.get({ plain: true });
- user.payments = await db.Payment.findAll({
+ params = {
order: [["id", "DESC"]],
where: {
user_id: user.id,
@@ -35,13 +42,20 @@ getUser = async username => {
model: db.Account,
as: "account"
}
- });
+ };
+
+ if (transaction) {
+ params.lock = transaction.LOCK.UPDATE;
+ params.transaction = transaction;
+ }
+
+ user.payments = await db.Payment.findAll(params);
return user;
};
-getUserById = async id => {
- let user = await db.User.findOne({
+getUserById = async (id, transaction) => {
+ let params = {
include: [
{
model: db.Account,
@@ -53,11 +67,18 @@ getUserById = async id => {
}
],
where: { id }
- });
+ };
+
+ if (transaction) {
+ params.lock = transaction.LOCK.UPDATE;
+ params.transaction = transaction;
+ }
+
+ let user = await db.User.findOne(params);
user = user.get({ plain: true });
- user.payments = await db.Payment.findAll({
+ params = {
order: [["id", "DESC"]],
where: {
user_id: user.id,
@@ -74,7 +95,14 @@ getUserById = async id => {
model: db.Account,
as: "account"
}
- });
+ };
+
+ if (transaction) {
+ params.lock = transaction.LOCK.UPDATE;
+ params.transaction = transaction;
+ }
+
+ user.payments = await db.Payment.findAll(params);
return user;
};
diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js
index deded625..1aae1467 100644
--- a/routes/bitcoin/receive.js
+++ b/routes/bitcoin/receive.js
@@ -73,10 +73,22 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
addresses[user.address] = user.username;
+ let totalOutputs = tx.outs.reduce((a, b) => a + b.value, 0);
+ let totalInputs = 0;
+ for (let i = 0; i < tx.ins.length; i++) {
+ let { hash, index } = tx.ins[i];
+ hash = reverse(hash).toString("hex");
+ let hex = await bc.getRawTransaction(hash.toString('hex'));
+ let inputTx = bitcoin.Transaction.fromHex(hex);
+ totalInputs += inputTx.outs[index].value;
+ }
+ let fee = totalInputs - totalOutputs;
+
let payment = await db.Payment.create({
account_id: account.id,
user_id: user.id,
hash,
+ fee,
amount: value - tip,
currency,
rate,
diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js
index 42027f71..d9324028 100644
--- a/routes/bitcoin/send.js
+++ b/routes/bitcoin/send.js
@@ -31,7 +31,7 @@ module.exports = async (req, res) => {
total = total - change + fee;
let amount = total - fee;
- l.info("attempting bitcoin payment", user.username, total, change, amount, fee);
+ l.info("attempting bitcoin payment", user.username, { total, change, amount, fee });
let account, params;
try {
@@ -46,7 +46,7 @@ module.exports = async (req, res) => {
});
if (total > account.balance) {
- l.error("amount exceeds balance", amount, fee, balance);
+ l.error("amount exceeds balance", amount, fee, account.balance);
throw new Error("insufficient funds");
}
diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js
index 403eb999..980d9e01 100644
--- a/routes/lightning/receive.js
+++ b/routes/lightning/receive.js
@@ -27,6 +27,7 @@ const handlePayment = async msg => {
hash,
amount,
currency,
+ preimage: msg.r_preimage.toString('hex'),
rate,
received: true,
confirmed: true,
@@ -53,7 +54,7 @@ const handlePayment = async msg => {
"lightning payment received",
user.username,
payment.amount,
- payment.tip
+ payment.tip,
);
};
diff --git a/routes/lightning/send.js b/routes/lightning/send.js
index 22c7627a..d273471a 100644
--- a/routes/lightning/send.js
+++ b/routes/lightning/send.js
@@ -15,93 +15,78 @@ module.exports = async (req, res) => {
try {
await db.transaction(async transaction => {
- let { balance } = await db.User.findOne(
- {
- where: {
- username: user.username
- }
+ let account = await db.Account.findOne({
+ where: {
+ user_id: user.id,
+ asset: config.liquid.btcasset
},
- { transaction }
- );
+ lock: transaction.LOCK.UPDATE,
+ transaction
+ });
- if (balance < payreq.satoshis) {
- throw new Error("insufficient funds");
+ if (account.balance < payreq.satoshis) {
+ throw new Error("Insufficient funds");
}
- user.balance -= payreq.satoshis;
- await user.save({ transaction });
- });
- } catch (e) {
- l.warn(
- "insufficient funds for lightning payment",
- user.username,
- user.balance
- );
- return res.status(500).send("Not enough satoshis");
- }
+ let m = await lna.sendPaymentSync({
+ payment_request: hash
+ });
- let m;
- try {
- let paymentHash = payreq.tags.find(t => t.tagName === "payment_hash").data;
- m = await lna.sendPaymentSync({
- payment_request: hash
- });
+ if (m.payment_error) return res.status(500).send(m.payment_error);
- if (m.payment_error) return res.status(500).send(m.payment_error);
+ if (seen.includes(m.payment_preimage)) {
+ l.warn("duplicate payment detected", m.payment_preimage);
+ throw new Error("Duplicate payment detected");
+ }
- if (seen.includes(m.payment_preimage)) {
- l.warn("duplicate payment detected", m.payment_preimage);
- return res.status(500).send("duplicate payment detected");
- }
+ let total = parseInt(m.payment_route.total_amt);
+ let fee = m.payment_route.total_fees;
- let total = parseInt(m.payment_route.total_amt);
- let fee = m.payment_route.total_fees;
+ account.balance -= total;
+ await account.save({ transaction });
- const account = await db.Account.findOne({
- where: {
+ let payment = await db.Payment.create({
+ amount: -total,
+ account_id: account.id,
user_id: user.id,
- asset: config.liquid.btcasset
- }
- });
-
- account.balance -= total - payreq.satoshis;
- await account.save()
-
- let payment = await db.Payment.create({
- amount: -total,
- account_id: account.id,
- user_id: user.id,
- hash,
- rate: app.get("rates")[user.currency],
- currency: user.currency,
- confirmed: true,
- network: "LNBTC"
- });
+ hash,
+ preimage: m.payment_preimage.toString("hex"),
+ rate: app.get("rates")[user.currency],
+ currency: user.currency,
+ confirmed: true,
+ network: "LNBTC"
+ }, { transaction });
- payment = payment.get({ plain: true });
- payment.account = account.get({ plain: true });
+ 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(m.payment_preimage);
+ l.info("sent lightning", user.username, -payment.amount);
- user = await getUser(user.username);
- emit(user.username, "user", user);
+ user = await getUser(user.username, transaction);
+ emit(user.username, "user", user);
- if (payreq.payeeNodeKey === config.lnb.id) {
- lna.addInvoice({ value: payreq.satoshis }, (err, invoice) => {
- let payback = lnb.sendPayment(lnb.meta, {});
+ if (payreq.payeeNodeKey === config.lnb.id) {
+ lna.addInvoice({ value: payreq.satoshis }, (err, invoice) => {
+ let payback = lnb.sendPayment(lnb.meta, {});
- /* eslint-disable-next-line */
- let { payment_request } = invoice;
- /* eslint-disable-next-line */
- payback.write({ payment_request });
- });
- }
+ /* eslint-disable-next-line */
+ let { payment_request } = invoice;
+ /* eslint-disable-next-line */
+ payback.write({ payment_request });
+ });
+ }
- seen.push(hash);
- res.send(payment);
+ seen.push(hash);
+ res.send(payment);
+ });
} catch (e) {
- l.info("error sending lightning", e.message);
- return res.status(500).send(e);
+ l.error(
+ "problem sending lightning payment",
+ user.username,
+ user.balance,
+ e.message
+ );
+ return res.status(500).send(e.message);
}
};