diff options
| author | Adam Soltys <[email protected]> | 2020-08-16 21:34:13 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2020-08-16 21:34:13 -0700 |
| commit | 7ab3036cb1576fe38ba1fd423a58b7cd97a58579 (patch) | |
| tree | 305b1a0aa321389b60385009876bbdb1fe0a1c68 /routes | |
| parent | b2208797d3c5559c7e8cc7d35b7a020da0c61193 (diff) | |
| download | coinos-server-7ab3036cb1576fe38ba1fd423a58b7cd97a58579.tar.gz coinos-server-7ab3036cb1576fe38ba1fd423a58b7cd97a58579.zip | |
non-custodial liquid wallets
Diffstat (limited to 'routes')
| -rw-r--r-- | routes/bitcoin/broadcast.js | 3 | ||||
| -rw-r--r-- | routes/bitcoin/receive.js | 22 | ||||
| -rw-r--r-- | routes/invoices.js | 1 | ||||
| -rw-r--r-- | routes/liquid/broadcast.js | 36 | ||||
| -rw-r--r-- | routes/liquid/fee.js | 19 | ||||
| -rw-r--r-- | routes/liquid/receive.js | 134 | ||||
| -rw-r--r-- | routes/liquid/send.js | 7 | ||||
| -rw-r--r-- | routes/payments.js | 22 | ||||
| -rw-r--r-- | routes/swaps.js | 1 | ||||
| -rw-r--r-- | routes/users.js | 13 |
10 files changed, 172 insertions, 86 deletions
diff --git a/routes/bitcoin/broadcast.js b/routes/bitcoin/broadcast.js index c7b134ac..4324e0d9 100644 --- a/routes/bitcoin/broadcast.js +++ b/routes/bitcoin/broadcast.js @@ -19,12 +19,13 @@ module.exports = ah(async (req, res) => { network: "BTC", }); - account.balance -= payment.amount + payment.fee; + account.balance += payment.amount - payment.fee; await account.save(); payment = payment.get({ plain: true }); payment.account = account.get({ plain: true }); emit(user.username, "payment", payment); + emit(user.username, "account", payment.account); res.send(payment); } else { res.send(result); diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js index ec120605..987f5079 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -1,6 +1,7 @@ const reverse = require("buffer-reverse"); const zmq = require("zeromq"); const { Op } = require("sequelize"); +const { fromBase58 } = require("bip32"); const bitcoin = require("bitcoinjs-lib"); @@ -35,7 +36,10 @@ zmqRawTx.on("message", async (topic, message, sequence) => { return; } - if (Object.keys(addresses).includes(address) && !change.includes(address)) { + if ( + Object.keys(addresses).includes(address) && + !change.includes(address) + ) { payments.push(hash); let user = await db.User.findOne({ @@ -55,7 +59,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => { const currency = invoice ? invoice.currency : user.currency; const rate = invoice ? invoice.rate : app.get("rates")[user.currency]; const tip = invoice ? invoice.tip : 0; - const memo = invoice ? invoice.memo : ''; + const memo = invoice ? invoice.memo : ""; let confirmed = false; @@ -66,7 +70,19 @@ zmqRawTx.on("message", async (topic, message, sequence) => { }, }); - let account = accounts.find(a => a.address === address); + let account = accounts.find(({ index, pubkey }) => { + const { payments } = bitcoin; + index && + pubkey && + address === + payments.p2wpkh({ + pubkey: fromBase58(pubkey, network).derivePath( + `${index}` + ).publicKey, + network, + }).address; + }); + if (!account) account = accounts[0]; account.pending += value; diff --git a/routes/invoices.js b/routes/invoices.js index ba4da254..511d6c02 100644 --- a/routes/invoices.js +++ b/routes/invoices.js @@ -26,6 +26,7 @@ app.post("/invoice", ah(async (req, res, next) => { } if (!user) throw new Error("user not provided"); invoice.user_id = user.id; + invoice.account_id = user.account_id; l.info( "creating invoice", diff --git a/routes/liquid/broadcast.js b/routes/liquid/broadcast.js new file mode 100644 index 00000000..e3709597 --- /dev/null +++ b/routes/liquid/broadcast.js @@ -0,0 +1,36 @@ +module.exports = ah(async (req, res) => { + try { + const { user } = req; + let hash = await lq.sendRawTransaction(req.body.tx); + + if (user) { + let { account } = user; + let payment = await db.Payment.create({ + ...req.body.payment, + hash, + amount: -req.body.payment.amount, + tip: 0, + account_id: account.id, + user_id: user.id, + rate: app.get("rates")[user.currency], + currency: user.currency, + confirmed: true, + received: false, + network: "LBTC", + }); + + account.balance += payment.amount - payment.fee; + await account.save(); + + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); + emit(user.username, "payment", payment); + emit(user.username, "account", payment.account); + res.send(payment); + } else { + res.send(result); + } + } catch (e) { + res.status(500).send(e.message); + } +}); diff --git a/routes/liquid/fee.js b/routes/liquid/fee.js index 77a9ce17..acf28160 100644 --- a/routes/liquid/fee.js +++ b/routes/liquid/fee.js @@ -1,8 +1,20 @@ +const buildTx = require("../../lib/buildliquidtx"); + module.exports = ah(async (req, res) => { let { user } = req; let { address, asset, amount, feeRate } = req.body; let tx, fee; + if (user.account.pubkey) { + try { + let psbt = await buildTx({ address, asset, amount, feeRate, user }); + return res.send(psbt); + } catch(e) { + throw e; + return res.status(500).send(e.message); + } + } + let invoice = await db.Invoice.findOne({ where: { address }, include: { @@ -13,8 +25,11 @@ module.exports = ah(async (req, res) => { }); if (invoice) { - emit(user.username, "to", invoice.user); - return res.end(); + let { ismine } = await lq.getAddressInfo(address); + if (ismine) { + emit(user.username, "to", invoice.user); + return res.end(); + } } try { diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index 3fe235a6..325e6783 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -1,7 +1,53 @@ const axios = require("axios"); +const reverse = require("buffer-reverse"); const zmq = require("zeromq"); const { Op } = require("sequelize"); +const { fromBase58 } = require("bip32"); +const bitcoin = require("bitcoinjs-lib"); const elements = require("elementsjs-lib"); +const liquid = require("liquidjs-lib"); + +const network = + liquid.networks[ + config.liquid.network === "mainnet" ? "liquid" : config.liquid.network + ]; + +const getAccount = async (params, pending) => { + let account = await db.Account.findOne({ + where: params + }); + + if (account) return account; + + let { asset } = params; + let name = asset.substr(0, 6); + let domain = ""; + let ticker = asset.substr(0, 3).toUpperCase(); + let precision = 8; + + const assets = (await axios.get("https://assets.blockstream.info/")).data; + + if (assets[asset]) { + ({ domain, ticker, precision, name } = assets[asset]); + } else { + const existing = await db.Account.findOne({ + where: { + asset, + }, + order: [["id", "ASC"]], + limit: 1, + }); + + if (existing) { + ({ domain, ticker, precision, name } = existing); + } + } + + params = { ...params, ...{ domain, ticker, precision, name } }; + params.balance = 0; + params.pending = pending; + return db.Account.create(params); +}; const zmqRawBlock = zmq.socket("sub"); zmqRawBlock.connect(config.liquid.zmqrawblock); @@ -26,77 +72,50 @@ zmqRawTx.on("message", async (topic, message, sequence) => { const value = toSats(o.value); const address = o.scriptPubKey.addresses[0]; - if (Object.keys(addresses).includes(address)) { + if ( + Object.keys(addresses).includes(address) && + !change.includes(address) + ) { let user = await getUser(addresses[address]); - let confirmed = 0; + let invoice = await db.Invoice.findOne({ + where: { + address, + user_id: user.id, + network: "LBTC", + }, + order: [["id", "DESC"]], + include: { + model: db.Account, + as: "account", + }, + }); - let params = { - user_id: user.id, - asset, - }; + if (!invoice) return; - let account = await db.Account.findOne({ - where: params, - }); + let confirmed = 0; - if (account) { + let { account } = invoice; + + if (account.asset === asset) { account.pending += value; await account.save(); } else { - let name = asset.substr(0, 6); - let domain = ''; - let ticker = asset.substr(0, 3).toUpperCase(); - let precision = 8; - - const assets = (await axios.get("https://assets.blockstream.info/")) - .data; - - if (assets[asset]) { - ({ domain, ticker, precision, name } = assets[asset]); - } else { - const existing = await db.Account.findOne({ - where: { - asset, - }, - order: [["id", "ASC"]], - limit: 1, - }); - - if (existing) { - ({ domain, ticker, precision, name } = existing); - } - } - - params = { ...params, ...{ domain, ticker, precision, name } }; - params.balance = 0; - params.pending = value; - account = await db.Account.create(params); + if (!account) account = await getAccount( + { + user_id: user.id, + asset, + pubkey: account.pubkey, + }, + value + ); } if (config.liquid.walletpass) await lq.walletPassphrase(config.liquid.walletpass, 300); - user.confidential = await lq.getNewAddress(); - user.liquid = ( - await lq.getAddressInfo(user.confidential) - ).unconfidential; - await user.save(); - addresses[user.liquid] = user.username; - - let invoice; - if (asset === config.liquid.btcasset) { - invoice = await db.Invoice.findOne({ - where: { - user_id: user.id, - network: "LBTC", - }, - order: [["id", "DESC"]], - }); - } - const currency = invoice ? invoice.currency : user.currency; const rate = invoice ? invoice.rate : app.get("rates")[user.currency]; const tip = invoice ? invoice.tip : 0; @@ -123,7 +142,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => { emit(user.username, "payment", payment); emit(user.username, "account", account); - l.info("liquid detected", user.username, asset, value); + l.info("liquid detected", address, user.username, asset, value); notify(user, `${value} SAT payment detected`); } }) @@ -218,6 +237,7 @@ zmqRawBlock.on("message", async (topic, message, sequence) => { }); setInterval(async () => { + // throw new Error("boom"); try { const arr = Object.keys(queue); diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 1d12db30..7f7e1cb5 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -39,8 +39,9 @@ module.exports = ah(async (req, res) => { await db.transaction(async (transaction) => { for (let i = 0; i < assets.length; i++) { let asset = assets[i]; - let total = totals[asset]; - if (change[asset]) total -= change[asset]; + let amount = totals[asset]; + if (change[asset]) amount -= change[asset]; + let total = amount; if (asset === config.liquid.btcasset) total += fee; l.info("creating liquid payment", user.username, asset, total, fee); @@ -67,7 +68,7 @@ module.exports = ah(async (req, res) => { await account.save({ transaction }); let payment = { - amount: -total, + amount: -amount, account_id: account.id, fee, memo, diff --git a/routes/payments.js b/routes/payments.js index ca479026..5e7263da 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -18,19 +18,12 @@ ah(async () => { l.warn("couldn't read exceptions file", e.message); } - await db.User.findAll({ - attributes: ["username", "address", "liquid"], - }).map((u) => { - if (u.address) addresses[u.address] = u.username; - if (u.liquid) addresses[u.liquid] = u.username; - }); - - await db.Invoice.findAll({ + (await db.Invoice.findAll({ include: { model: db.User, as: "user", }, - }).map(({ address, user, unconfidential }) => { + })).map(({ address, user, unconfidential }) => { if (address && user) addresses[address] = user.username; if (unconfidential && user) addresses[unconfidential] = user.username; }); @@ -113,7 +106,11 @@ ah(async () => { if (config.bitcoin) { bc = new BitcoinCore(config.bitcoin); - app.post("/bitcoin/broadcast", optionalAuth, require("./bitcoin/broadcast")); + app.post( + "/bitcoin/broadcast", + optionalAuth, + require("./bitcoin/broadcast") + ); app.get("/bitcoin/generate", auth, require("./bitcoin/generate")); app.post("/bitcoin/sweep", auth, require("./bitcoin/sweep")); app.post("/bitcoin/fee", auth, require("./bitcoin/fee")); @@ -123,6 +120,11 @@ ah(async () => { if (config.liquid) { lq = new BitcoinCore(config.liquid); + app.post( + "/liquid/broadcast", + optionalAuth, + require("./liquid/broadcast") + ); app.get("/liquid/generate", auth, require("./liquid/generate")); app.post("/liquid/fee", auth, require("./liquid/fee")); app.post("/liquid/send", auth, require("./liquid/send")); diff --git a/routes/swaps.js b/routes/swaps.js index 733e261f..71c35733 100644 --- a/routes/swaps.js +++ b/routes/swaps.js @@ -408,7 +408,6 @@ checkQueue = async () => { leveldb .createReadStream() .on("data", async function (data) { - console.log("pushing", data.key); txs.push({ ...JSON.parse(data.value), key: data.key }); }) .on("end", async function (data) { diff --git a/routes/users.js b/routes/users.js index ececd37b..58738b72 100644 --- a/routes/users.js +++ b/routes/users.js @@ -157,10 +157,6 @@ app.post( sockets[username] = sockets[user.username]; user.username = username; - if (user.address) addresses[user.address] = username; - - if (user.liquid) addresses[user.liquid] = user.username; - token = jwt.sign({ username }, config.jwt); res.cookie("token", token, { expires: new Date(Date.now() + 432000000), @@ -223,17 +219,16 @@ app.post( "/accounts", auth, ah(async (req, res) => { - const { address, pubkey } = req.body; + const { name, pubkey, ticker } = req.body; const { user } = req; let account = await db.Account.create({ - address, user_id: user.id, asset: config.liquid.btcasset, balance: 0, pending: 0, - name: "Bitcoin", - ticker: "BTC", + name, + ticker, precision: 8, pubkey, }); @@ -375,7 +370,7 @@ app.post( const account = await db.Account.findOne({ where: { id }, - }); + }); emit(user.username, "account", account); res.end(); |
