diff options
| author | Adam Soltys <[email protected]> | 2020-04-24 22:46:45 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2020-04-28 22:33:02 -0700 |
| commit | fae6e8b55ea12989d688eb777c002222199c169b (patch) | |
| tree | 3efed4974408fc1bc8911aa9fb9fc657456d69ee | |
| parent | 306357c24d3014b55ae1cd25b954a695ea2e5cc6 (diff) | |
| download | coinos-server-fae6e8b55ea12989d688eb777c002222199c169b.tar.gz coinos-server-fae6e8b55ea12989d688eb777c002222199c169b.zip | |
improved assets support
| -rw-r--r-- | db/index.js | 10 | ||||
| -rw-r--r-- | db/models/accounts.js | 27 | ||||
| -rw-r--r-- | db/models/payments.js | 13 | ||||
| -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 | 85 | ||||
| -rw-r--r-- | lib/whitelist.js | 8 | ||||
| -rw-r--r-- | routes/balances.js | 13 | ||||
| -rw-r--r-- | routes/bitcoin/receive.js | 49 | ||||
| -rw-r--r-- | routes/bitcoin/send.js | 3 | ||||
| -rw-r--r-- | routes/lightning/receive.js | 32 | ||||
| -rw-r--r-- | routes/lightning/send.js | 82 | ||||
| -rw-r--r-- | routes/lightning/user.js | 2 | ||||
| -rw-r--r-- | routes/liquid/receive.js | 89 | ||||
| -rw-r--r-- | routes/liquid/send.js | 148 | ||||
| -rw-r--r-- | routes/users.js | 24 |
18 files changed, 353 insertions, 313 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..8c464293 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, @@ -55,14 +64,14 @@ const attributes = { comment: null, field: "rate" }, - asset: { + network: { type: DataTypes.STRING(255), allowNull: true, defaultValue: null, primaryKey: false, autoIncrement: false, comment: null, - field: "asset" + field: "network" }, currency: { type: DataTypes.STRING(255), 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..2f0214d5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,30 +1,69 @@ 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 + } }, - { + limit: 12, + include: { model: db.Account, - as: "accounts" + as: "account" } - ], - where: - { [Op.or]: { username, id: username }} - }); - } + }, + { + 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, + include: { + model: db.Account, + as: "account" + } + }, + { + model: db.Account, + as: "accounts" + }, + { + model: db.Account, + as: "account" + } + ], + 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..74afb4fb 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -12,7 +12,6 @@ const zmqRawTx = zmq.socket("sub"); zmqRawTx.connect(config.bitcoin.zmqrawtx); zmqRawTx.subscribe("rawtx"); -const asset = "BTC"; const network = bitcoin.networks[ config.bitcoin.network === "mainnet" ? "bitcoin" : config.bitcoin.network @@ -48,7 +47,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => { const invoice = await db.Invoice.findOne({ where: { user_id: user.id, - asset + network: 'BTC', }, order: [["id", "DESC"]] }); @@ -59,15 +58,25 @@ zmqRawTx.on("message", async (topic, message, sequence) => { let confirmed = false; - user.address = await bc.getNewAddress("", "bech32"); - user.pending += value; + const account = await db.Account.findOne({ + where: { + user_id: user.id, + asset: config.liquid.btcasset + } + }); + + account.pending += value; + await account.save(); + user.address = await bc.getNewAddress("", "bech32"); await user.save(); + user = await getUser(user.username); emit(user.username, "user", user); addresses[user.address] = user.username; const payment = await db.Payment.create({ + account_id: account.id, user_id: user.id, hash, amount: value - tip, @@ -77,7 +86,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => { tip, confirmed, address, - asset, + network: 'BTC' }); l.info("bitcoin detected", user.username, o.value); @@ -109,33 +118,23 @@ setInterval(async () => { let hash = arr[i]; let p = await db.Payment.findOne({ - include: [{ model: db.User, as: "user" }], - where: { hash, confirmed: 0 } + where: { hash, confirmed: 0, received: 1 }, + include: { + model: db.Account, + as: "account" + } }); p.confirmed = 1; + p.account.balance += p.amount + p.tip; + p.account.pending -= Math.min(p.account.pending, p.amount + p.tip); - let user = await p.getUser(); - user.balance += p.amount + p.tip; - user.pending -= Math.min(user.pending, p.amount + p.tip); - emit(user.username, "user", user); - - await user.save(); + await p.account.save(); await p.save(); - let payments = await db.Payment.findAll({ - where: { - user_id: user.id, - received: { - [Op.ne]: null - } - }, - order: [["id", "DESC"]], - limit: 12 - }); - + let user = await getUserById(p.user_id); + emit(user.username, "user", user); l.info("bitcoin confirmed", user.username, p.amount, p.tip); - emit(user.username, "payments", payments); delete queue[hash]; } }, 1000); diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index 948e5386..bb0cf97b 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -72,6 +72,7 @@ module.exports = async (req, res) => { { amount: -total, fee, + account_id: user.account.id, user_id: user.id, hash: txid, rate: app.get("rates")[user.currency], @@ -79,7 +80,7 @@ module.exports = async (req, res) => { address, confirmed: true, received: false, - asset: "BTC" + network: "BTC" }, { transaction } ); 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..0d2025ad 100644 --- a/routes/lightning/send.js +++ b/routes/lightning/send.js @@ -32,66 +32,76 @@ 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 payment = await db.Payment.create( - { - amount: -total, - fee, - user_id: user.id, - hash, - rate: app.get("rates")[user.currency], - currency: user.currency, - confirmed: true, - asset: 'LNBTC', - }, - { transaction } - ); + const account = await db.Account.findOne({ + where: { + user_id: user.id, + asset: config.liquid.btcasset + } + }); - seen.push(m.payment_preimage); + const 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" + }); - l.info("sent lightning", user.username, -payment.amount); - emit(user.username, "payment", payment); - emit(user.username, "user", user); + user = await getUser(user.username); - if (payreq.payeeNodeKey === config.lnb.id) { - lna.addInvoice({ value: payreq.satoshis }, (err, invoice) => { - let payback = lnb.sendPayment(lnb.meta, {}); + seen.push(m.payment_preimage); - /* eslint-disable-next-line */ - let { payment_request } = invoice; - /* eslint-disable-next-line */ - payback.write({ payment_request }); - }); - } + l.info("sent lightning", user.username, -payment.amount); + emit(user.username, "payment", payment); - seen.push(hash); - res.send(payment); - }); + l.info("user payments", user.payments); + emit(user.username, "user", user); + + 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 }); + }); + } + + seen.push(hash); + res.send(payment); } catch (e) { l.info("error sending lightning", e); return res.status(500).send(e); diff --git a/routes/lightning/user.js b/routes/lightning/user.js index 34659a6c..36af2718 100644 --- a/routes/lightning/user.js +++ b/routes/lightning/user.js @@ -34,7 +34,7 @@ module.exports = async (req, res) => { tip: 0, confirmed: true, received: false, - asset: "LNBTC" + network : "LNBTC" }); req.url = "/lightning/send"; diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index 24d17a35..5d7eb237 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,29 @@ 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, - }; + let 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/"); + + if (assets[asset]) { + 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(); @@ -76,11 +79,13 @@ zmqRawTx.on("message", async (topic, message, sequence) => { )).unconfidential; await user.save(); + user = await getUser(user.username); emit(user.username, "user", user); 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, @@ -90,7 +95,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => { tip, confirmed, address, - asset + network: "LBTC" }); payments.push(blinded.txid); @@ -126,48 +131,24 @@ setInterval(async () => { let hash = arr[i]; let p = await db.Payment.findOne({ - where: { hash, confirmed: 0, received: 1 } - }); - - const user = await getUser(p.user_id); - - p.confirmed = 1; - - const asset = await db.Account.findOne({ - where: { - user_id: user.id, - asset: p.asset + where: { hash, confirmed: 0, received: 1 }, + include: { + model: db.Account, + as: "account" } }); - 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("liquid confirmed", user.username, p.asset, p.amount, p.tip); - emit(user.username, "user", user); + p.confirmed = 1; + p.account.balance += p.amount + p.tip; + p.account.pending -= Math.min(p.account.pending, p.amount + p.tip); - await user.save(); + await p.account.save(); await p.save(); - let payments = await db.Payment.findAll({ - where: { - user_id: user.id, - received: { - [Op.ne]: null - } - }, - order: [["id", "DESC"]], - limit: 12 - }); + let user = await getUserById(p.user_id); + emit(user.username, "user", user); + l.info("liquid confirmed", user.username, p.asset, p.amount, p.tip); - emit(user.username, "payments", payments); delete queue[hash]; } }, 1000); diff --git a/routes/liquid/send.js b/routes/liquid/send.js index e1a7e473..461b0c0a 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -4,96 +4,104 @@ module.exports = async (req, res) => { let { user } = req; let { address, - asset, tx: { hex } } = req.body; - const isChange = async address => - ((await lq.getAddressInfo(address)).ismine) && - (!Object.keys(addresses).includes(address) || - address === user.liquid); + const isChange = async address => + (await lq.getAddressInfo(address)).ismine && + (!Object.keys(addresses).includes(address) || address === user.liquid); const unblinded = await lq.unblindRawTransaction(hex); tx = await lq.decodeRawTransaction(unblinded.hex); - - let total = 0; - let change = 0; + + let totals = {}; + let change = {}; let fee = 0; for (let i = 0; i < tx.vout.length; i++) { - let o = tx.vout[i]; - total += toSats(o.value); - if (o.scriptPubKey.type === 'fee') fee = toSats(o.value); - - if (o.scriptPubKey.addresses) { - if ((await isChange(o.scriptPubKey.addresses[0]))) { - change += toSats(o.value); + let { + asset, + value, + scriptPubKey: { type, addresses } + } = tx.vout[i]; + + if (!totals[asset]) totals[asset] = change[asset] = 0; + totals[asset] += toSats(value); + if (type === "fee") fee = toSats(value); + + if (addresses) { + if (await isChange(addresses[0])) { + change[asset] += toSats(value); } } - } + } - total = total - change; - let amount = total - fee; + let assets = Object.keys(totals); + for (let i = 0; i < assets.length; i++) { + let asset = assets[i]; + let total = totals[asset]; + if (change[asset]) total -= change[asset]; - l.info("attempting liquid payment", user.username, amount, fee); + l.info("attempting liquid payment", user.username, asset, total, fee); - try { - await db.transaction(async transaction => { - let { balance } = await db.User.findOne({ - where: { - username: user.username - }, - lock: transaction.LOCK.UPDATE, - transaction - }); + try { + await db.transaction(async transaction => { + let account = await db.Account.findOne({ + where: { + user_id: user.id, + asset + }, + lock: transaction.LOCK.UPDATE, + transaction + }); - if (amount !== balance && total > balance) { - l.warn("amount exceeds balance", { amount, fee, balance }); - throw new Error("insufficient funds"); - } + if (total > account.balance) { + l.warn("amount exceeds balance", { + total, + fee, + balance: account.balance + }); + throw new Error("insufficient funds"); + } - req.user.balance -= total; - await user.save({ transaction }); - }); - } catch (e) { - l.warn("insufficient funds for liquid payment", user.username); - return res.status(500).send("Not enough satoshis"); - } + account.balance -= total; + await account.save({ transaction }); - try { - if (config.liquid.walletpass) - await lq.walletPassphrase(config.liquid.walletpass, 300); + try { + if (config.liquid.walletpass) + await lq.walletPassphrase(config.liquid.walletpass, 300); - hex = await lq.blindRawTransaction(hex); - rawtx = (await lq.signRawTransactionWithWallet(hex)).hex; - let txid = await lq.sendRawTransaction(rawtx); + hex = await lq.blindRawTransaction(hex); + rawtx = (await lq.signRawTransactionWithWallet(hex)).hex; + let txid = await lq.sendRawTransaction(rawtx); - await db.transaction(async transaction => { - await user.save({ transaction }); - emit(user.username, "user", user); + const payment = await db.Payment.create({ + amount: -total, + account_id: account.id, + fee, + user_id: user.id, + hash: txid, + rate: app.get("rates")[user.currency], + currency: user.currency, + address, + confirmed: true, + received: false, + network: "LBTC" + }, { transaction }); - const payment = await db.Payment.create( - { - amount: -total, - fee, - user_id: user.id, - hash: txid, - rate: app.get("rates")[user.currency], - currency: user.currency, - address, - confirmed: true, - received: false, - asset: 'LBTC' - }, - { transaction } - ); + payment.account = account; - l.info("sent liquid", user.username, total); - emit(user.username, "payment", payment); - res.send(payment); - }); - } catch (e) { - l.error("liquid send failed", e); - return res.status(500).send(e.message); + user = await getUser(user.username); + emit(user.username, "user", user); + res.send(payment); + } catch (e) { + l.error("liquid send failed", e); + return res.status(500).send(e.message); + } + }); + } catch (e) { + l.warn("insufficient funds for liquid payment", user.username, e.message); + return res.status(500).send("Not enough satoshis"); + } } }; diff --git a/routes/users.js b/routes/users.js index 1d9a4f3d..cc7b62cc 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, @@ -66,8 +71,9 @@ const gift = async user => { rate: app.get("rates")[user.currency], received: true, confirmed: 1, - asset: "GIFT" + network: "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)); }); |
