aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--db/index.js10
-rw-r--r--db/models/accounts.js27
-rw-r--r--db/models/payments.js9
-rw-r--r--db/models/users.js78
-rw-r--r--index.js1
-rw-r--r--lib/passport.js1
-rw-r--r--lib/sockets.js1
-rw-r--r--lib/utils.js79
-rw-r--r--lib/whitelist.js8
-rw-r--r--routes/balances.js13
-rw-r--r--routes/bitcoin/receive.js3
-rw-r--r--routes/lightning/receive.js32
-rw-r--r--routes/lightning/send.js36
-rw-r--r--routes/liquid/receive.js80
-rw-r--r--routes/liquid/send.js1
-rw-r--r--routes/users.js22
16 files changed, 211 insertions, 190 deletions
diff --git a/db/index.js b/db/index.js
index bb94fb98..215d34df 100644
--- a/db/index.js
+++ b/db/index.js
@@ -28,6 +28,11 @@ db["User"].hasMany(db["Payment"], {
foreignKey: "user_id"
});
+db["User"].belongsTo(db["Account"], {
+ as: "account",
+ foreignKey: "account_id"
+});
+
db["Account"].belongsTo(db["User"], {
as: "user",
foreignKey: "user_id"
@@ -38,6 +43,11 @@ db["Invoice"].belongsTo(db["User"], {
foreignKey: "user_id"
});
+db["Payment"].belongsTo(db["Account"], {
+ as: "account",
+ foreignKey: "account_id"
+});
+
db["Payment"].belongsTo(db["User"], {
as: "user",
foreignKey: "user_id"
diff --git a/db/models/accounts.js b/db/models/accounts.js
index aeaf8d5e..a4b38992 100644
--- a/db/models/accounts.js
+++ b/db/models/accounts.js
@@ -37,6 +37,24 @@ const attributes = {
comment: null,
field: "updatedAt"
},
+ name: {
+ type: DataTypes.STRING(255),
+ allowNull: true,
+ defaultValue: null,
+ primaryKey: false,
+ autoIncrement: false,
+ comment: null,
+ field: "name"
+ },
+ ticker: {
+ type: DataTypes.STRING(255),
+ allowNull: true,
+ defaultValue: null,
+ primaryKey: false,
+ autoIncrement: false,
+ comment: null,
+ field: "ticker"
+ },
asset: {
type: DataTypes.STRING(255),
allowNull: true,
@@ -64,6 +82,15 @@ const attributes = {
comment: null,
field: "pending"
},
+ precision: {
+ type: DataTypes.DOUBLE,
+ allowNull: true,
+ defaultValue: null,
+ primaryKey: false,
+ autoIncrement: false,
+ comment: null,
+ field: "precision"
+ },
};
const options = {
diff --git a/db/models/payments.js b/db/models/payments.js
index c6dd6e83..4859bce7 100644
--- a/db/models/payments.js
+++ b/db/models/payments.js
@@ -10,6 +10,15 @@ const attributes = {
comment: null,
field: "id"
},
+ account_id: {
+ type: DataTypes.INTEGER(11),
+ allowNull: true,
+ defaultValue: null,
+ primaryKey: false,
+ autoIncrement: false,
+ comment: null,
+ field: "account_id"
+ },
user_id: {
type: DataTypes.INTEGER(11),
allowNull: true,
diff --git a/db/models/users.js b/db/models/users.js
index 48e8c94f..439ddb63 100644
--- a/db/models/users.js
+++ b/db/models/users.js
@@ -64,14 +64,14 @@ const attributes = {
comment: null,
field: "address"
},
- symbol: {
- type: DataTypes.STRING(255),
+ account_id: {
+ type: DataTypes.INTEGER(11),
allowNull: true,
defaultValue: null,
primaryKey: false,
autoIncrement: false,
comment: null,
- field: "symbol"
+ field: "account_id"
},
otpsecret: {
type: DataTypes.STRING(255),
@@ -100,24 +100,6 @@ const attributes = {
comment: null,
field: "currencies"
},
- pubkey: {
- type: DataTypes.STRING(255),
- allowNull: true,
- defaultValue: null,
- primaryKey: false,
- autoIncrement: false,
- comment: null,
- field: "pubkey"
- },
- privkey: {
- type: DataTypes.STRING(255),
- allowNull: true,
- defaultValue: null,
- primaryKey: false,
- autoIncrement: false,
- comment: null,
- field: "privkey"
- },
createdAt: {
type: DataTypes.DATE,
allowNull: false,
@@ -145,42 +127,6 @@ const attributes = {
comment: null,
field: "index"
},
- balance: {
- type: DataTypes.INTEGER(11),
- allowNull: false,
- defaultValue: "0",
- primaryKey: false,
- autoIncrement: false,
- comment: null,
- field: "balance"
- },
- channel: {
- type: DataTypes.STRING(255),
- allowNull: true,
- defaultValue: null,
- primaryKey: false,
- autoIncrement: false,
- comment: null,
- field: "channel"
- },
- readonlypw: {
- type: DataTypes.STRING(255),
- allowNull: true,
- defaultValue: null,
- primaryKey: false,
- autoIncrement: false,
- comment: null,
- field: "readonlypw"
- },
- limit: {
- type: DataTypes.INTEGER(11),
- allowNull: true,
- defaultValue: "0",
- primaryKey: false,
- autoIncrement: false,
- comment: null,
- field: "limit"
- },
fbtoken: {
type: DataTypes.STRING(255),
allowNull: true,
@@ -190,24 +136,6 @@ const attributes = {
comment: null,
field: "fbtoken"
},
- friend: {
- type: DataTypes.INTEGER(1),
- allowNull: true,
- defaultValue: null,
- primaryKey: false,
- autoIncrement: false,
- comment: null,
- field: "friend"
- },
- pending: {
- type: DataTypes.INTEGER(11),
- allowNull: true,
- defaultValue: "0",
- primaryKey: false,
- autoIncrement: false,
- comment: null,
- field: "pending"
- },
name: {
type: DataTypes.STRING(255),
allowNull: true,
diff --git a/index.js b/index.js
index 0ff00cc5..376810b2 100644
--- a/index.js
+++ b/index.js
@@ -20,6 +20,7 @@ app.use(compression());
server = require("http").Server(app);
require("./db");
+require("./lib/utils");
require("./lib/sockets");
require("./lib/passport");
require("./lib/rates");
diff --git a/lib/passport.js b/lib/passport.js
index 81f4e948..e0c2dd62 100644
--- a/lib/passport.js
+++ b/lib/passport.js
@@ -1,6 +1,5 @@
const Passport = require("passport");
const jwt = require("passport-jwt");
-const { getUser } = require("./utils");
function cookieExtractor(req) {
if (req && req.cookies) return req.cookies["token"];
diff --git a/lib/sockets.js b/lib/sockets.js
index ad7295b0..9a5457c3 100644
--- a/lib/sockets.js
+++ b/lib/sockets.js
@@ -1,6 +1,5 @@
const jwt = require("jsonwebtoken");
const io = require("socket.io");
-const { getUser } = require("./utils");
/* eslint-disable-next-line */
const pick = (O, ...K) => K.reduce((o, k) => ((o[k] = O[k]), o), {});
diff --git a/lib/utils.js b/lib/utils.js
index 7784ae5c..7b4b1668 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -1,30 +1,57 @@
const { Op } = require("sequelize");
-module.exports = {
- async getUser(username) {
- return db.User.findOne({
- include: [
- {
- model: db.Payment,
- as: "payments",
- order: [["id", "DESC"]],
- where: {
- [Op.or]: {
- received: true,
- amount: {
- [Op.lt]: 0
- }
+getUser = async username => {
+ return db.User.findOne({
+ include: [
+ {
+ model: db.Payment,
+ as: "payments",
+ order: [["id", "DESC"]],
+ where: {
+ [Op.or]: {
+ received: true,
+ amount: {
+ [Op.lt]: 0
}
- },
- limit: 12
+ }
},
- {
- model: db.Account,
- as: "accounts"
- }
- ],
- where:
- { [Op.or]: { username, id: username }}
- });
- }
-};
+ limit: 12
+ },
+ {
+ model: db.Account,
+ as: "accounts"
+ },
+ {
+ model: db.Account,
+ as: "account"
+ }
+ ],
+ where: { username },
+ });
+}
+
+getUserById = async id => {
+ return db.User.findOne({
+ include: [
+ {
+ model: db.Payment,
+ as: "payments",
+ order: [["id", "DESC"]],
+ where: {
+ [Op.or]: {
+ received: true,
+ amount: {
+ [Op.lt]: 0
+ }
+ }
+ },
+ limit: 12
+ },
+ {
+ model: db.Account,
+ as: "accounts"
+ }
+ ],
+ where: { id }
+ });
+}
diff --git a/lib/whitelist.js b/lib/whitelist.js
index e5f672b2..8af95820 100644
--- a/lib/whitelist.js
+++ b/lib/whitelist.js
@@ -1,5 +1,7 @@
whitelist = [
'id',
+'account',
+'account_id',
'unit',
'fbtoken',
'username',
@@ -7,11 +9,13 @@ whitelist = [
'symbol',
'currency',
'currencies',
-'balance',
-'pending',
'name',
'pic',
'twofa',
'liquid',
'confidential',
+'accounts',
+'payments',
+'balance',
+'pending',
]
diff --git a/routes/balances.js b/routes/balances.js
index eff361ea..86658ed3 100644
--- a/routes/balances.js
+++ b/routes/balances.js
@@ -9,11 +9,6 @@ app.get("/balances", async (req, res) => {
[sequelize.fn("sum", sequelize.col("balance")), "total"]
],
group: ["asset"],
- where: {
- asset: {
- [Op.ne]: config.liquid.btcasset
- }
- }
});
const balances = {
@@ -23,13 +18,6 @@ app.get("/balances", async (req, res) => {
liquid: parseInt(assets.bitcoin * SATS),
lnchannel: parseInt((await lna.channelBalance({})).balance),
lnwallet: parseInt((await lna.walletBalance({})).total_balance),
- user: parseInt(
- (await db["User"].findAll({
- attributes: [[sequelize.fn("sum", sequelize.col("balance")), "total"]],
- raw: true,
- order: sequelize.literal("total DESC")
- }))[0].total
- )
};
const { bitcoin, liquid, lnchannel, user, lnwallet } = balances;
@@ -42,6 +30,5 @@ app.get("/balances", async (req, res) => {
balances.ratio = (balances.total / parseInt(user)).toFixed(2);
-
res.send(balances);
});
diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js
index 3083c49c..ff93df16 100644
--- a/routes/bitcoin/receive.js
+++ b/routes/bitcoin/receive.js
@@ -109,13 +109,12 @@ setInterval(async () => {
let hash = arr[i];
let p = await db.Payment.findOne({
- include: [{ model: db.User, as: "user" }],
where: { hash, confirmed: 0 }
});
p.confirmed = 1;
- let user = await p.getUser();
+ const user = await getUserById(p.user_id);
user.balance += p.amount + p.tip;
user.pending -= Math.min(user.pending, p.amount + p.tip);
emit(user.username, "user", user);
diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js
index 6ac4c947..c300d8ea 100644
--- a/routes/lightning/receive.js
+++ b/routes/lightning/receive.js
@@ -4,19 +4,29 @@ const handlePayment = async msg => {
if (!msg.settled) return;
const invoice = await db.Invoice.findOne({
- include: { model: db.User, as: "user" },
where: {
text: msg.payment_request
}
});
+
if (!invoice) return;
- const { text: hash, currency, rate, tip, user } = invoice;
+ const { text: hash, currency, rate, tip, user_id } = invoice;
const amount = parseInt(msg.value) - tip;
+ let user = await getUserById(user_id);
+
+ const account = await db.Account.findOne({
+ where: {
+ user_id,
+ asset: config.liquid.btcasset
+ }
+ });
+
const payment = await db.Payment.create({
- user_id: user.id,
+ account_id: account.id,
+ user_id,
hash,
amount,
currency,
@@ -24,17 +34,27 @@ const handlePayment = async msg => {
received: true,
confirmed: true,
asset,
- tip,
+ tip
});
invoice.received += amount + tip;
- user.balance += amount + tip;
+ account.balance += amount + tip;
+ await account.save();
await invoice.save();
await payment.save();
await user.save();
+
payments.push(msg.payment_request);
- l.info("lightning payment received", user.username, payment.amount, payment.tip);
+ l.info(
+ "lightning payment received",
+ user.username,
+ payment.amount,
+ payment.tip
+ );
+
+ user = await getUser(user.username)
+ l.info(user.account.balance);
emit(user.username, "payment", payment);
emit(user.username, "user", user);
diff --git a/routes/lightning/send.js b/routes/lightning/send.js
index 822fe0e4..c2551896 100644
--- a/routes/lightning/send.js
+++ b/routes/lightning/send.js
@@ -32,50 +32,63 @@ module.exports = async (req, res) => {
await user.save({ transaction });
});
} catch (e) {
- l.warn("insufficient funds for lightning payment", user.username, user.balance);
+ l.warn(
+ "insufficient funds for lightning payment",
+ user.username,
+ user.balance
+ );
return res.status(500).send("Not enough satoshis");
}
let m;
try {
- let paymentHash = payreq.tags.find(t => t.tagName === 'payment_hash').data;
+ let paymentHash = payreq.tags.find(t => t.tagName === "payment_hash").data;
m = await lna.sendPaymentSync({
- "payment_request": hash,
+ payment_request: hash
});
-
+
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);
return res.status(500).send("duplicate payment detected");
- }
+ }
let total = parseInt(m.payment_route.total_amt);
let fee = m.payment_route.total_fees;
user.balance -= total - payreq.satoshis;
- await db.transaction(async transaction => {
- await user.save({ transaction });
+ await user.save();
+
+ const account = await db.Account.findOne({
+ where: {
+ user_id: user.id,
+ asset: config.liquid.btcasset
+ }
+ });
const payment = await db.Payment.create(
{
amount: -total,
- fee,
+ account_id: account.id,
user_id: user.id,
hash,
rate: app.get("rates")[user.currency],
currency: user.currency,
confirmed: true,
- asset: 'LNBTC',
- },
- { transaction }
+ asset: "LNBTC"
+ }
);
+ user = await getUser(user.username);
+
seen.push(m.payment_preimage);
l.info("sent lightning", user.username, -payment.amount);
emit(user.username, "payment", payment);
+
+ l.info("user payments", user.payments);
emit(user.username, "user", user);
if (payreq.payeeNodeKey === config.lnb.id) {
@@ -91,7 +104,6 @@ module.exports = async (req, res) => {
seen.push(hash);
res.send(payment);
- });
} catch (e) {
l.info("error sending lightning", e);
return res.status(500).send(e);
diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js
index 24d17a35..8d2d6ca8 100644
--- a/routes/liquid/receive.js
+++ b/routes/liquid/receive.js
@@ -1,3 +1,4 @@
+const axios = require("axios");
const reverse = require("buffer-reverse");
const zmq = require("zeromq");
const { Op } = require("sequelize");
@@ -47,27 +48,26 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
let confirmed = 0;
- if (asset === config.liquid.btcasset) {
- user.pending += value;
- } else {
- const params = {
- user_id: user.id,
- asset,
- };
+ const params = {
+ user_id: user.id,
+ asset,
+ };
- const account = await db.Account.findOne({
- where: params
- });
+ const account = await db.Account.findOne({
+ where: params
+ });
- if (account) {
- account.pending += value;
- await account.save();
- } else {
- params.balance = 0;
- params.pending = value;
- l.info("creating", params);
- await db.Account.create(params);
- }
+ if (account) {
+ account.pending += value;
+ await account.save();
+ } else {
+ let assets = await axios.get("https://assets.blockstream.info/");
+ let { ticker, precision, name } = assets[asset];
+ params = { ...params, ...{ticker, precision, name }};
+
+ params.balance = 0;
+ params.pending = value;
+ account = await db.Account.create(params);
}
user.confidential = await lq.getNewAddress();
@@ -81,6 +81,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
addresses[user.liquid] = user.username;
const payment = await db.Payment.create({
+ account_id: account.id,
user_id: user.id,
hash: blinded.txid,
amount: value - tip,
@@ -127,47 +128,26 @@ setInterval(async () => {
let p = await db.Payment.findOne({
where: { hash, confirmed: 0, received: 1 }
+ include: {
+ model: db.Account,
+ as: "account",
+ },
});
- const user = await getUser(p.user_id);
-
p.confirmed = 1;
- const asset = await db.Account.findOne({
- where: {
- user_id: user.id,
- asset: p.asset
- }
- });
-
- l.info("asset", p.asset);
- if (p.asset === config.liquid.btcasset) {
- user.balance += p.amount + p.tip;
- user.pending -= Math.min(user.pending, p.amount + p.tip);
- } else {
- asset.balance += p.amount + p.tip;
- asset.pending -= Math.min(user.pending, p.amount + p.tip);
- await asset.save();
- }
+ l.info("account", p.account);
+ p.account.balance += p.amount + p.tip;
+ p.account.pending -= Math.min(p.account.pending, p.amount + p.tip);
+ await p.account.save();
l.info("liquid confirmed", user.username, p.asset, p.amount, p.tip);
- emit(user.username, "user", user);
- await user.save();
await p.save();
- let payments = await db.Payment.findAll({
- where: {
- user_id: user.id,
- received: {
- [Op.ne]: null
- }
- },
- order: [["id", "DESC"]],
- limit: 12
- });
+ user = await getUser(user.username);
+ emit(user.username, "user", user);
- emit(user.username, "payments", payments);
delete queue[hash];
}
}, 1000);
diff --git a/routes/liquid/send.js b/routes/liquid/send.js
index e1a7e473..b0660929 100644
--- a/routes/liquid/send.js
+++ b/routes/liquid/send.js
@@ -15,6 +15,7 @@ module.exports = async (req, res) => {
const unblinded = await lq.unblindRawTransaction(hex);
tx = await lq.decodeRawTransaction(unblinded.hex);
+ l.info("decoded", tx);
let total = 0;
let change = 0;
diff --git a/routes/users.js b/routes/users.js
index 1d9a4f3d..b1e83a4c 100644
--- a/routes/users.js
+++ b/routes/users.js
@@ -4,7 +4,6 @@ const jwt = require("jsonwebtoken");
const uuidv4 = require("uuid/v4");
const fb = "https://graph.facebook.com/";
const authenticator = require("otplib").authenticator;
-const { getUser } = require("../lib/utils");
const pick = (O, ...K) => K.reduce((o, k) => ((o[k] = O[k]), o), {});
let faucet = 1000;
@@ -55,10 +54,16 @@ app.get("/liquidate", async (req, res) => {
});
const gift = async user => {
+ const account = user.accounts[0];
+
if (faucet > 0) {
- user.balance = 100;
faucet -= 100;
+
+ account.balance = 100;
+ await account.save();
+
const payment = await db.Payment.create({
+ account_id: account.id,
user_id: user.id,
hash: "Welcome Gift",
amount: 100,
@@ -68,6 +73,7 @@ const gift = async user => {
confirmed: 1,
asset: "GIFT"
});
+
await user.save();
}
};
@@ -109,8 +115,20 @@ app.post("/register", async (req, res) => {
addresses[user.address] = user.username;
addresses[user.liquid] = user.username;
user = await db.User.create(user);
+
+ let account = await db.Account.create({
+ user_id: user.id,
+ asset: config.liquid.btcasset,
+ balance: 0,
+ pending: 0,
+ });
+
+ user.accounts = [account];
await gift(user);
+ user.account_id = account.id;
+ await user.save();
+
l.info("new user", user.username);
res.send(pick(user, ...whitelist));
});