diff options
| -rw-r--r-- | db/index.js | 10 | ||||
| -rw-r--r-- | db/models/accounts.js | 27 | ||||
| -rw-r--r-- | db/models/payments.js | 9 | ||||
| -rw-r--r-- | db/models/users.js | 78 | ||||
| -rw-r--r-- | index.js | 1 | ||||
| -rw-r--r-- | lib/passport.js | 1 | ||||
| -rw-r--r-- | lib/sockets.js | 1 | ||||
| -rw-r--r-- | lib/utils.js | 79 | ||||
| -rw-r--r-- | lib/whitelist.js | 8 | ||||
| -rw-r--r-- | routes/balances.js | 13 | ||||
| -rw-r--r-- | routes/bitcoin/receive.js | 3 | ||||
| -rw-r--r-- | routes/lightning/receive.js | 32 | ||||
| -rw-r--r-- | routes/lightning/send.js | 36 | ||||
| -rw-r--r-- | routes/liquid/receive.js | 80 | ||||
| -rw-r--r-- | routes/liquid/send.js | 1 | ||||
| -rw-r--r-- | routes/users.js | 22 |
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, @@ -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)); }); |
