From fdbbb5af05c46a203032575a55ac66b655c801f1 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 10 Jun 2021 17:24:14 -0400 Subject: remove build endpoint --- index.js | 68 ---------------------------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/index.js b/index.js index b7f8c6ba..4866691f 100644 --- a/index.js +++ b/index.js @@ -70,7 +70,6 @@ require("./lib/notifications"); require("./lib/register"); require("./lib/send"); - require("./routes/assets"); require("./routes/invoices"); require("./routes/payments"); @@ -82,73 +81,6 @@ require("./routes/funding"); if (config.lnurl) require("./routes/lnurl"); if (config.imap) require("./lib/mail"); - -const sigHeaderName = "X-Hub-Signature-256"; -const sigHashAlg = "sha256"; -function verifyPostData(req, res, next) { - try { - if (!req.rawBody) { - return next("Request body empty"); - } - - const sig = Buffer.from(req.get(sigHeaderName) || "", "utf8"); - const hmac = crypto.createHmac(sigHashAlg, config.github); - const digest = Buffer.from( - sigHashAlg + "=" + hmac.update(req.rawBody).digest("hex"), - "utf8" - ); - - if (sig.length !== digest.length || !crypto.timingSafeEqual(digest, sig)) { - return next( - `Request body digest (${digest}) did not match ${sigHeaderName} (${sig})` - ); - } - } catch (e) { - console.log(e.message); - } - - return next(); -} - -app.post("/build", (req, res) => { - const mailgun = require("mailgun-js")(config.mailgun); - let data = { - subject: "Build started", - text: `Build started at ${new Date()}`, - from: "adam@coinos.io", - to: "build@coinos.io" - }; - - mailgun.messages().send(data); - l.info("build starting"); - fs.writeFileSync("build.json", req.body.payload); - - const { exec } = require("child_process"); - exec("bash build.sh", (error, stdout, stderr) => { - if (error) { - data = { - subject: "Build error", - text: `Build failed at ${new Date()}`, - from: "adam@coinos.io", - to: "build@coinos.io" - }; - - mailgun.messages().send(data); - l.warn("build failed"); - } else { - data = { - subject: "Build finished", - text: `Build finished at ${new Date()}`, - from: "adam@coinos.io", - to: "build@coinos.io" - }; - - mailgun.messages().send(data); - l.info("build finished"); - } - }); -}); - app.use((err, req, res, next) => { const details = { path: req.path, -- cgit v1.2.3 From e343c8b07794a86156601efebe58b443b15b10da Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 17 Jun 2021 17:05:09 -0400 Subject: add fee to total --- routes/liquid/send.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 19b7344f..6455736c 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -75,12 +75,12 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { await faucet.reload({ transaction }); await faucet.save({ transaction }); } - - total += fee - covered; } + + total += fee - covered; } - if (limit && total > limit) + if (limit && total > limit + fee) throw new Error("Tx amount exceeds authorized amount"); if (asset !== btc || total) { -- cgit v1.2.3 From de06cbf6141679b2e10ca01bee1e372efc356c91 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 24 Jun 2021 02:52:33 -0400 Subject: only send on-chain after db transaction --- routes/bitcoin/send.js | 55 +++++++++++++++++++++++++------------------------- routes/liquid/fee.js | 7 +------ routes/liquid/send.js | 28 ++++++++++++++----------- routes/payments.js | 12 +++++++---- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index cab79e06..470889b3 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -1,4 +1,3 @@ -const bitcoin = require("bitcoinjs-lib"); const btc = config.liquid.btcasset; module.exports = ah(async (req, res) => { @@ -32,10 +31,10 @@ module.exports = ah(async (req, res) => { total = total - change + fee; let amount = total - fee; - let params; + let account, params; try { await db.transaction(async transaction => { - let account = await db.Account.findOne({ + account = await db.Account.findOne({ where: { id: user.account_id }, @@ -62,38 +61,38 @@ module.exports = ah(async (req, res) => { await account.decrement({ balance: total }, { transaction }); await account.reload({ transaction }); + }); - params = { - amount: -amount, - fee, - memo, - account_id: account.id, - user_id: user.id, - rate: app.get("rates")[user.currency], - currency: user.currency, - address, - confirmed: true, - received: false, - network: "bitcoin" - }; + params = { + amount: -amount, + fee, + memo, + account_id: account.id, + user_id: user.id, + rate: app.get("rates")[user.currency], + currency: user.currency, + address, + confirmed: true, + received: false, + network: "bitcoin" + }; - if (config.bitcoin.walletpass) - await bc.walletPassphrase(config.bitcoin.walletpass, 300); + if (config.bitcoin.walletpass) + await bc.walletPassphrase(config.bitcoin.walletpass, 300); - hex = (await bc.signRawTransactionWithWallet(hex)).hex; - params.hash = await bc.sendRawTransaction(hex); + hex = (await bc.signRawTransactionWithWallet(hex)).hex; + params.hash = await bc.sendRawTransaction(hex); - let payment = await db.Payment.create(params, { transaction }); + let payment = await db.Payment.create(params); - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); - emit(user.username, "payment", payment); - res.send(payment); + emit(user.username, "payment", payment); + res.send(payment); - payments.push(params.hash); - l.info("sent bitcoin", user.username, total); - }); + payments.push(params.hash); + l.info("sent bitcoin", user.username, total); } catch (e) { l.error("error sending bitcoin", e.message); return res.status(500).send(e.message); diff --git a/routes/liquid/fee.js b/routes/liquid/fee.js index 2070873a..a6c29f41 100644 --- a/routes/liquid/fee.js +++ b/routes/liquid/fee.js @@ -3,11 +3,6 @@ const buildTx = require("../../lib/buildliquidtx"); liquidTx = async ({ address, asset, amount, feeRate, replaceable, user }) => { let tx, fee; let node = lq; - /* - if (asset === config.liquid.btcasset) { - node = rare; - } - */ if (user.account.pubkey) { let psbt = await buildTx({ @@ -81,7 +76,7 @@ module.exports = ah(async (req, res) => { let tx = await liquidTx({ ...req.body, user: req.user }) res.send(tx); } catch (e) { - l.error("error estimating liquid fee", e.message, e.stack); + l.error("error estimating liquid fee", e.message); return res.status(500).send(e.message); } }); diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 6455736c..13f77d26 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -1,5 +1,6 @@ const btc = config.liquid.btcasset; const lcad = config.liquid.cadasset; +const { Transaction } = require("liquidjs-lib"); sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { if (amount > 10000000) throw new Error("Amount too large"); @@ -48,7 +49,8 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { const assets = Object.keys(totals); const payments = []; - return db.transaction(async transaction => { + let main, signed; + await db.transaction(async transaction => { for (let i = 0; i < assets.length; i++) { let asset = assets[i]; let amount = totals[asset]; @@ -132,16 +134,11 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { } } - if (config.liquid.walletpass) - await lq.walletPassphrase(config.liquid.walletpass, 300); + signed = await lq.signRawTransactionWithWallet( + await lq.blindRawTransaction(tx.hex) + ); + let txid = Transaction.fromHex(signed.hex).getId(); - let blinded = await lq.blindRawTransaction(tx.hex); - let signed = await lq.signRawTransactionWithWallet(blinded); - let txid = await lq.sendRawTransaction(signed.hex); - - l.info("sent liquid tx", txid, address); - - let main; for (let i = 0; i < assets.length; i++) { p = payments[i]; if (p) { @@ -157,15 +154,22 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { emit(user.username, "account", main.account); emit(user.username, "payment", main); - return main; }); + + if (config.liquid.walletpass) + await lq.walletPassphrase(config.liquid.walletpass, 300); + + let txid = await lq.sendRawTransaction(signed.hex); + l.info("sent liquid tx", txid, address); + + return main; }; module.exports = ah(async (req, res) => { let { user } = req; try { - res.send(await sendLiquid({...req.body, user })); + res.send(await sendLiquid({ ...req.body, user })); } catch (e) { l.error("problem sending liquid", user.username, e.message); return res.status(500).send(e); diff --git a/routes/payments.js b/routes/payments.js index e8e94d8a..86c0dd15 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -138,10 +138,14 @@ ah(async () => { require("./liquid/receive"); setTimeout(async () => { - const address = await lq.getNewAddress(); - const { hdkeypath } = await lq.getAddressInfo(address); - const parts = hdkeypath.split("/"); - app.set("lqAddressIndex", parts[parts.length - 1].slice(0, -1)); + try { + const address = await lq.getNewAddress(); + const { hdkeypath } = await lq.getAddressInfo(address); + const parts = hdkeypath.split("/"); + app.set("lqAddressIndex", parts[parts.length - 1].slice(0, -1)); + } catch(e) { + console.log("Problem getting liquid address", e.message); + } }, 50); } -- cgit v1.2.3 From 36a05a441a6be0a1a270802c9a38a2265a7b775e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 24 Jun 2021 02:52:43 -0400 Subject: contact form handler --- lib/mail.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/mail.js b/lib/mail.js index 705880d2..9780fab7 100644 --- a/lib/mail.js +++ b/lib/mail.js @@ -10,6 +10,22 @@ function openInbox(cb) { imap.openBox("INBOX", true, cb); } +app.post( + "/contact", + ah((req, res) => { + const mailgun = require("mailgun-js")(config.mailgun); + let data = { + subject: "Contact form", + text: JSON.stringify(req.body), + from: "server@coinos.io", + to: "contact@coinos.io" + }; + + mailgun.messages().send(data); + res.send(req.body); + }) +); + imap.once("ready", function() { openInbox(function(err, box) { if (err) throw err; -- cgit v1.2.3 From 3fedd98ccd302589dcf21cb1152a6132bfcb35fc Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 24 Jun 2021 02:52:51 -0400 Subject: pm2 upgrade --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae280704..d8985205 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "devDependencies": { "nodemon": "^2.0.2", "pino-pretty": "^3.6.1", - "pm2": "^4.5.6", + "pm2": "^5.1.0", "prettier": "^1.18.2" } } -- cgit v1.2.3 From 3ff26389ca9854d7d34ed28d3f034b2d32938872 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 24 Jun 2021 06:32:21 -0400 Subject: invoice amount validation --- routes/invoices.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/routes/invoices.js b/routes/invoices.js index cc8549e1..93528d60 100644 --- a/routes/invoices.js +++ b/routes/invoices.js @@ -27,6 +27,10 @@ app.post( let { liquidAddress, invoice, user, tx } = req.body; let { blindkey } = invoice; + if (invoice.amount < 0) throw new Error("amount out of range"); + if (invoice.tip > invoice.amount || invoice.tip > 1000000 || invoice.tip < 0) + throw new Error("tip amount out of range"); + if (liquidAddress) { l.info("conversion request for", liquidAddress, invoice.text); convert[invoice.text] = { address: liquidAddress, tx }; @@ -43,7 +47,7 @@ app.post( if (!user) throw new Error("user not provided"); if (!invoice.currency) invoice.currency = user.currency; if (!invoice.rate) invoice.rate = app.get("rates")[invoice.currency]; - if (invoice.tip > invoice.amount || invoice.tip > 1000000) throw new Error("tip is too large") + invoice.user_id = user.id; invoice.account_id = user.account_id; @@ -54,7 +58,7 @@ app.post( invoice.amount, invoice.tip, invoice.currency, - `${invoice.text.substr(0, 8)}..${invoice.text.substr(-6)}`, + `${invoice.text.substr(0, 8)}..${invoice.text.substr(-6)}` ); if (!invoice.tip) invoice.tip = 0; -- cgit v1.2.3 From 9e6091525bfa1e068fa4592b48acd8fa9d8a7fc5 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 30 Jun 2021 14:59:30 -0400 Subject: handle address failure --- routes/payments.js | 2 +- routes/users.js | 23 ++++++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/routes/payments.js b/routes/payments.js index 86c0dd15..fe8092a9 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -144,7 +144,7 @@ ah(async () => { const parts = hdkeypath.split("/"); app.set("lqAddressIndex", parts[parts.length - 1].slice(0, -1)); } catch(e) { - console.log("Problem getting liquid address", e.message); + l.warn("Problem getting liquid address index", e.message); } }, 50); } diff --git a/routes/users.js b/routes/users.js index 09ba5d43..25a737ce 100644 --- a/routes/users.js +++ b/routes/users.js @@ -160,7 +160,8 @@ app.post( return res.status(500).send("Username taken"); } else { sockets[username] = sockets[user.username]; - if (user.username !== username) l.info("changing username", user.username, username); + if (user.username !== username) + l.info("changing username", user.username, username); user.username = username; token = jwt.sign({ username }, config.jwt); @@ -335,10 +336,7 @@ app.post( (user.password && !(await bcrypt.compare(req.body.password, user.password))) ) { - l.warn( - "invalid username or password attempt", - req.body.username - ); + l.warn("invalid username or password attempt", req.body.username); return res.status(401).end(); } @@ -438,11 +436,22 @@ app.get( : config.liquid.network ]; type = "p2sh"; - + // async request to node to bump its internal index but don't use result - lq.getNewAddress().catch(console.error); + lq.getNewAddress().catch((e) => l.warn("Problem bumping liquid address index", e.message)) i = parseInt(app.get("lqAddressIndex")); + + if (!i) { + const { hdkeypath } = await lq.getAddressInfo( + await lq.getNewAddress() + ); + const parts = hdkeypath.split("/"); + i = parts[parts.length - 1].slice(0, -1); + } + + if (!i) throw new Error("Problem generating address"); + hd = fromBase58(config.liquid.masterkey, n).derivePath(`m/0'/0'/${i}'`); app.set("lqAddressIndex", i + 1); } else { -- cgit v1.2.3 From 8a554b6d3085efc3e4b062bdb0ac61cc0ce89416 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 8 Jul 2021 15:14:57 -0400 Subject: check that token can decode properly --- lib/sockets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sockets.js b/lib/sockets.js index 931a9d23..bd59ee38 100644 --- a/lib/sockets.js +++ b/lib/sockets.js @@ -96,7 +96,7 @@ wss.on("connection", function(ws, req) { lastSeen[token] = new Date(); try { - if (!token || token === "null") return ws.close(); + if (!token || token === "null" || !jwt.decode(token)) return ws.close(); const username = jwt.decode(token).username; if (!username) throw new Error("Invalid JWT token"); -- cgit v1.2.3 From 556b133ffbd4591b49626c821d7602e09e97a1f2 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 8 Jul 2021 15:15:14 -0400 Subject: throw instead of returning to abort db transaction --- routes/send.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/send.js b/routes/send.js index 579e70b4..3aec9fb6 100644 --- a/routes/send.js +++ b/routes/send.js @@ -45,7 +45,7 @@ module.exports = ah(async (req, res, next) => { }; if (!username) { - return res.status(500).send("Vouchers temporarily disabled"); + throw new Error("Vouchers temporarily disabled"); l.info("creating redeemable payment"); params.redeemcode = uuidv4(); params.hash = `${req.get("origin")}/redeem/${params.redeemcode}`; -- cgit v1.2.3 From 300ccc094a9c5261a42479ce4f241655dbd190e1 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 8 Jul 2021 15:16:18 -0400 Subject: ignore balance watcher script --- .gitignore | 1 + watcher.sh | 20 -------------------- 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100755 watcher.sh diff --git a/.gitignore b/.gitignore index b3bbeb6d..131e61c6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ lnurl-server.sqlite3 watcher.log build.json build.sh +watcher.sh diff --git a/watcher.sh b/watcher.sh deleted file mode 100755 index 3fb60993..00000000 --- a/watcher.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -sats=100000000 -threshold=$1 -while true -do - ln=$(lncli --lnddir=/root/.lnda --network=mainnet --chain=bitcoin --rpcserver=localhost:10001 channelbalance | jr .balance) - bc=$(bitcoin-cli getbalance) - el=$(elements-cli getbalance | jr .bitcoin) - total=$(node -pe "$ln + $bc * $sats + $el * $sats") - low=$(node -pe "$total < $threshold") - echo $(date -Is) ln $ln bc $bc el $el tot $total - if "$low"; then - echo "Threshold hit, setting new threshold" - threshold=$total - # yarn pm2 stop 0 > /dev/null - node /root/mailgun/index.js - fi - sleep 10 -done -- cgit v1.2.3 From 29956a035056c76b3329792feb9a7fb3d7c8ec0e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 8 Jul 2021 15:17:06 -0400 Subject: only convert btc --- routes/liquid/fee.js | 2 ++ routes/liquid/receive.js | 6 +++--- routes/users.js | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/routes/liquid/fee.js b/routes/liquid/fee.js index a6c29f41..fad69f13 100644 --- a/routes/liquid/fee.js +++ b/routes/liquid/fee.js @@ -59,6 +59,8 @@ liquidTx = async ({ address, asset, amount, feeRate, replaceable, user }) => { } ); + l.info("funding tx for fee estimate", tx); + tx = await node.fundRawTransaction(tx, params); let blinded = await node.blindRawTransaction(tx.hex); diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index 05ecc21f..9d8923eb 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -287,9 +287,9 @@ setInterval(async () => { for (let i = 0; i < arr.length; i++) { const hash = arr[i]; - let account, address, user, total; + let account, address, user, total, p; await db.transaction(async transaction => { - let p = await db.Payment.findOne({ + p = await db.Payment.findOne({ where: { hash, confirmed: 0, received: 1 }, include: [ { @@ -343,7 +343,7 @@ setInterval(async () => { }); let c = convert[address]; - if (address && c) { + if (address && c && p.account.asset === network.assetHash) { l.info("liquid detected for conversion request", address, c.address, user.username); user.account = account; diff --git a/routes/users.js b/routes/users.js index 25a737ce..558d476d 100644 --- a/routes/users.js +++ b/routes/users.js @@ -438,7 +438,9 @@ app.get( type = "p2sh"; // async request to node to bump its internal index but don't use result - lq.getNewAddress().catch((e) => l.warn("Problem bumping liquid address index", e.message)) + lq.getNewAddress().catch(e => + l.warn("Problem bumping liquid address index", e.message) + ); i = parseInt(app.get("lqAddressIndex")); -- cgit v1.2.3 From eeecdd5fae55fc32a8582ce8b77ea097bfdb2b53 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Thu, 29 Jul 2021 15:11:19 -0400 Subject: Added to the regtest instructions Added commands to send bitcoin to your account, to use for testing. --- doc/fund-server-bitcoin-cli.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/fund-server-bitcoin-cli.md b/doc/fund-server-bitcoin-cli.md index 3c5b6ef5..5b096f0f 100644 --- a/doc/fund-server-bitcoin-cli.md +++ b/doc/fund-server-bitcoin-cli.md @@ -14,11 +14,19 @@ docker exec -it bitcoin bash bitcoin-cli -regtest -datadir=/config -rpcwallet=coinosdev getnewaddress # mine a block to the new address -bitcoin-cli -regtest -datadir=/config generatetoaddress 101 theaddressgneratedabove +bitcoin-cli -regtest -datadir=/config generatetoaddress 101 theaddressgeneratedabove # verify you got the reward: bitcoin-cli -regtest -datadir=/config -conf=./bitcoin.conf -rpcwallet=coinosdev getbalance > 50.00000000 + +# send 10 bitcoin to your account on the server +# get the address to send to from ./receive, select 'Bitcoin' +bitcoin-cli -regtest -datadir=/config -rpcwallet=coinosdev sendtoaddress [account-address] 10 + +# confirm the transaction +# (do the mining command again) +bitcoin-cli -regtest -datadir=/config generatetoaddress 101 theaddressgeneratedabove ``` ![](./img/50-bitcoin-server-balance.gif) -- cgit v1.2.3 From 038e14715e7030a7be1692efeb61b3576f2213b8 Mon Sep 17 00:00:00 2001 From: Ran Guin Date: Thu, 29 Jul 2021 13:09:55 -0700 Subject: update search condition generator --- scripts/apiParse.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/apiParse.js b/scripts/apiParse.js index 427f34cd..138a82f4 100644 --- a/scripts/apiParse.js +++ b/scripts/apiParse.js @@ -1,9 +1,10 @@ var debug = require('debug')('debug') -const addUserSearch = async function (input) { +const addUserSearch = function (input, table) { debug('add User Search') var {search, starts_with, contains} = input + if (!table) { table = 'Users' } // if (since) cmd = cmd.havingRaw('invoices + payments + deposits + orders > ?', [0]) if (search) { @@ -13,7 +14,7 @@ const addUserSearch = async function (input) { search = '%' + search + '%' } - var condition = "(Users.email like '" + search + " OR Users.username like '" + search + "'" + var condition = "(" + table + ".email like '" + search + "' OR " + table + ".username like '" + search + "')" debug('condition: ' + condition) return condition @@ -22,14 +23,14 @@ const addUserSearch = async function (input) { } } -const addTimeSearch = async function (input, field) { +const addTimeSearch = function (input, field) { debug('add time Search') if (!field) { field = 'updatedAt' } var {since} = input if (since) { - condition = "WHERE " + field + " >= " + since + condition = field + " >= '" + since + "'" debug('condition: ' + condition) return condition @@ -38,5 +39,8 @@ const addTimeSearch = async function (input, field) { } } -module.exports = {addUserSearch: addUserSearch, addTimeSearch: addTimeSearch} +module.exports = { + addUserSearch: addUserSearch, + addTimeSearch: addTimeSearch, +} -- cgit v1.2.3 From f61427a86cd14faac8f8501cd23d016a5942fa2a Mon Sep 17 00:00:00 2001 From: Ran Guin Date: Thu, 29 Jul 2021 13:10:17 -0700 Subject: use standardized search condition generator --- routes/admin.js | 224 ++++++++++++++------------------------------------------ 1 file changed, 56 insertions(+), 168 deletions(-) diff --git a/routes/admin.js b/routes/admin.js index c401c724..c7b7578d 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -35,20 +35,12 @@ router.get( .select('username', 'email', 'phone', 'verified', knex.raw('LEFT(createdAt,10) as created_at')) .from('users') - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } + var timeCondition = parseInput.addTimeSearch(req.query, 'users.createdAt') + var userCondition = parseInput.addUserSearch(req.query) - if (search) { - users = users - .where(function() { - this.where('username', 'like', search) - this.orWhere('email', 'like', search) - }) - } - debug('search ? ' + search) + if (timeCondition) users = users.whereRaw(timeCondition) + if (userCondition) users = users.whereRaw(userCondition) + // Alternative Sequelize query syntax // await db.User.findAll({ // attributes: ['username', 'email', 'phone', 'verified', 'createdAt'] @@ -101,6 +93,11 @@ router.get( // ] // }) + var timeCondition = parseInput.addTimeSearch(req.query, 'referrals.updatedAt') + var userCondition = parseInput.addUserSearch(req.query, 'sponsor') + + if (timeCondition) referrals = referrals.whereRaw(timeCondition) + if (userCondition) referrals = referrals.whereRaw(userCondition) debug('Referrals: ' + JSON.stringify(referrals)) return res.send({referrals: referrals}) @@ -141,20 +138,12 @@ router.get( .leftJoin('users', 'users.email', 'waiting_list.email') .where('waiting_list.id', '>', 0) - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } + var timeCondition = parseInput.addTimeSearch(req.query, 'waiting_list.updated_at') + var userCondition = parseInput.addUserSearch(req.query) + + if (timeCondition) queue = queue.whereRaw(timeCondition) + if (userCondition) queue = queue.whereRaw(userCondition) - if (search) { - queue = queue - .where(function() { - this.where('waiting_list.email', 'like', search) - this.orWhere('users.username', 'like', search) - }) - } - debug('search ? ' + search) const found = await queue debug('Waiting list: ' + JSON.stringify(found)) @@ -195,19 +184,12 @@ router.get( .where('balance', '>', 0) } - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } + var timeCondition = parseInput.addTimeSearch(req.query, 'accounts.updatedAt') + var userCondition = parseInput.addUserSearch(req.query) + + if (timeCondition) accounts = accounts.whereRaw(timeCondition) + if (userCondition) accounts = accounts.whereRaw(userCondition) - if (search) { - accounts = accounts - .where(function() { - this.where('users.email', 'like', search) - this.orWhere('users.username', 'like', search) - }) - } debug('search ? ' + search) const found = await accounts @@ -270,21 +252,11 @@ router.get( debug(types[i] + ' since ' + since) } } + if (since) transactions = transactions.havingRaw('invoices + payments + deposits + orders > ?', [0]) - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } - - if (search) { - transactions = transactions - .where(function() { - this.where('users.email', 'like', search) - this.orWhere('users.username', 'like', search) - }) - } + var userCondition = parseInput.addUserSearch(req.query) + if (userCondition) transactions = transactions.whereRaw(userCondition) transactions = transactions .groupBy('users.id') @@ -338,27 +310,16 @@ router.get( .leftJoin('users as u1', 'a1.user_id', 'u1.id') .leftJoin('users as u2', 'a2.user_id', 'u2.id') - if (since) { - orders = orders - .where('orders.updatedAt', '>=', since) - } + var timeCondition = parseInput.addTimeSearch(req.query, 'orders.updatedAt') + if (timeCondition) orders = orders.whereRaw(timeCondition) - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } - - if (search) { - orders = orders - .where( function () { - this.where('u1.email', 'like', search) - this.orWhere('u1.username', 'like', search) - this.orWhere('u2.username', 'like', search) - this.orWhere('u2.email', 'like', search) - }) - } - debug('orders since ' + since) + var userCondition1 = parseInput.addUserSearch(req.query, 'u1') + var userCondition2 = parseInput.addUserSearch(req.query, 'u2') + + if (userCondition1) orders = orders.where( function () { + this.whereRaw(userCondition1) + this.orWhere(knex.raw(userCondition2)) + }) var found = await orders debug('orders: ' + JSON.stringify(found)) @@ -403,26 +364,11 @@ router.get( .leftJoin('accounts', 'invoices.account_id', 'accounts.id') .leftJoin('users', 'accounts.user_id', 'users.id') - if (since) { - invoices = invoices - .where('invoices.updatedAt', '>=', since) - } - - debug('invoices since ' + since) - - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } + var timeCondition = parseInput.addTimeSearch(req.query, 'invoices.updatedAt') + var userCondition = parseInput.addUserSearch(req.query) - if (search) { - invoices = invoices - .where(function() { - this.where('users.email', 'like', search) - this.orWhere('users.username', 'like', search) - }) - } + if (timeCondition) invoices = invoices.whereRaw(timeCondition) + if (userCondition) invoices = invoices.whereRaw(userCondition) var found = await invoices debug('invoices: ' + JSON.stringify(found)) @@ -468,26 +414,11 @@ router.get( debug('dtype: ' + deposits.constructor + ' : ' + typeof(deposits)) - if (since) { - deposits = deposits - .where('deposits.updatedAt', '>=', since) - } - - debug('deposits since ' + since) - - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } + var timeCondition = parseInput.addTimeSearch(req.query, 'deposits.updatedAt') + var userCondition = parseInput.addUserSearch(req.query) - if (search) { - deposits = deposits - .where(function() { - this.where('users.email', 'like', search) - this.orWhere('users.username', 'like', search) - }) - } + if (timeCondition) deposits = deposits.whereRaw(timeCondition) + if (userCondition) deposits = deposits.whereRaw(userCondition) var found = await deposits debug('deposits: ' + JSON.stringify(found)) @@ -530,27 +461,11 @@ router.get( .from('withdrawals') .leftJoin('users', 'withdrawals.user_id', 'users.id') - if (since) { - withdrawals = withdrawals - .where('withdrawals.updatedAt', '>=', since) - } - - debug('withdrawals since ' + since) - - - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } + var timeCondition = parseInput.addTimeSearch(req.query, 'withdrawals.updatedAt') + var userCondition = parseInput.addUserSearch(req.query) - if (search) { - withdrawals = withdrawals - .where(function() { - this.where('users.email', 'like', search) - this.orWhere('users.username', 'like', search) - }) - } + if (timeCondition) withdrawals = withdrawals.whereRaw(timeCondition) + if (userCondition) withdrawals = withdrawals.whereRaw(userCondition) var found = await withdrawals debug('withdrawals: ' + JSON.stringify(found)) @@ -595,27 +510,12 @@ router.get( .leftJoin('accounts', 'payments.account_id', 'accounts.id') .leftJoin('users', 'accounts.user_id', 'users.id') - if (since) { - payments = payments - .where('payments.updatedAt', '>=', since) - } - - debug('payments since ' + since) - + var timeCondition = parseInput.addTimeSearch(req.query, 'payments.updatedAt') + var userCondition = parseInput.addUserSearch(req.query) - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } + if (timeCondition) payments = payments.whereRaw(timeCondition) + if (userCondition) payments = payments.whereRaw(userCondition) - if (search) { - payments = payments - .where(function() { - this.where('users.email', 'like', search) - this.orWhere('users.username', 'like', search) - }) - } var found = await payments debug('payments: ' + JSON.stringify(found)) return res.send({payments: found}) @@ -658,7 +558,9 @@ router.get( // 'payments.network', // knex.raw('LEFT(hash,20) as hash'), // knex.raw('Left(payments.updatedAt,16) as transferred') - ) + // knex.raw( parseInput.readableDate('Max(payments.updatedAt)', 'last_changed') ) + knex.raw( 'DATE_FORMAT(Max(payments.updatedAt), ?) AS last_changed', "%M %d, %Y" ) + ) .from('payments') .leftJoin('accounts', 'payments.account_id', 'accounts.id') .leftJoin('users', 'payments.user_id', 'users.id') // should really point to accounts @@ -666,30 +568,16 @@ router.get( // .groupBy('payments.currency') // .groupBy('payments.network') - if (since) { - kyc = kyc - .where('payments.updatedAt', '>=', since) - } - - debug('payments since ' + since) + var timeCondition = parseInput.addTimeSearch(req.query, 'payments.updatedAt') + var userCondition = parseInput.addUserSearch(req.query) - if (starts_with) { - search = search + '%' - } else if (contains) { - search = '%' + search + '%' - } + if (timeCondition) kyc = kyc.whereRaw(timeCondition) + if (userCondition) kyc = kyc.whereRaw(userCondition) - if (search) { - kyc = kyc - .where(function() { - this.where('users.email', 'like', search) - this.orWhere('users.username', 'like', search) - }) - } var found = await kyc.having('max', '>=', threshold) debug('payments: ' + JSON.stringify(found)) - return res.send({kyc_transactions: found}) + return res.send({found: found}) }) ); -- cgit v1.2.3 From 1d28ac4a070cf87465d8cf9bb1263341b51e3672 Mon Sep 17 00:00:00 2001 From: Ran Guin Date: Thu, 29 Jul 2021 13:10:42 -0700 Subject: include user_id for waiting_list --- routes/referrals.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/routes/referrals.js b/routes/referrals.js index 3bcce5b2..11cf8590 100644 --- a/routes/referrals.js +++ b/routes/referrals.js @@ -244,6 +244,7 @@ router.post( debug('email: ' + email) debug('phone: ' + phone) + debug('user_id: ' + user_id) await knex.table('waiting_list') .insert({ @@ -259,15 +260,17 @@ router.post( router.get( "/joinQueue", ah(async (req, res) => { - const {email, phone} = req.query; + const {email, phone, user_id} = req.query; debug('email: ' + email) debug('phone: ' + phone) + debug('user: ' + user_id) await knex('waiting_list') .insert({ email: email, - phone: phone + phone: phone, + user_id: user_id }) res.send({success: true, message: 'Added ' + email + ' to waiting list ' + phone}) -- cgit v1.2.3 From df86f50b1f08f24574c15eccf3fbe0daf5c42a5e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 29 Jul 2021 11:55:18 -0700 Subject: change overrides so default is to use a dev build rather than dev webpack --- .gitignore | 1 - docker-compose.dev.yml | 13 +++++++++++++ docker-compose.override.yml | 11 +++++++++++ docker-compose.yml | 9 --------- sample.override.yml | 13 ------------- 5 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 docker-compose.dev.yml create mode 100644 docker-compose.override.yml delete mode 100644 sample.override.yml diff --git a/.gitignore b/.gitignore index 2537982f..58f3c4fe 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,3 @@ lnurl-server.sqlite3 watcher.log config mysql -docker-compose.override.yml diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 00000000..00397499 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,13 @@ +version: '3.6' +services: + ui: + depends_on: + - app + container_name: ui + image: asoltys/coinos-ui:dev + ports: + - '8085:8085' + environment: + NODE_ENV: development + volumes: + - ../coinos-ui:/coinos diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 00000000..b7318355 --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,11 @@ +version: '3.6' +services: + ui: + container_name: ui + image: asoltys/coinos-ui + ports: + - 80:80 + volumes: + - ./config/nginx:/etc/nginx/templates + environment: + HOST: ${HOST} diff --git a/docker-compose.yml b/docker-compose.yml index ad004ad7..9e898822 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,5 @@ version: '3.6' services: - ui: - container_name: ui - image: asoltys/coinos-ui - ports: - - 80:80 - volumes: - - ./config/nginx:/etc/nginx/templates - environment: - HOST: ${HOST} app: container_name: app image: asoltys/coinos-server diff --git a/sample.override.yml b/sample.override.yml deleted file mode 100644 index 00397499..00000000 --- a/sample.override.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: '3.6' -services: - ui: - depends_on: - - app - container_name: ui - image: asoltys/coinos-ui:dev - ports: - - '8085:8085' - environment: - NODE_ENV: development - volumes: - - ../coinos-ui:/coinos -- cgit v1.2.3 From bca4fe152c83ab6a615a5e1601ca965187ee95e3 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 3 Aug 2021 01:40:44 -0700 Subject: fix docker dev path --- docker-compose.dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 00397499..c40a3ef1 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -10,4 +10,4 @@ services: environment: NODE_ENV: development volumes: - - ../coinos-ui:/coinos + - ../coinos-ui:/coinos-ui -- cgit v1.2.3 From 889e472f78660f4680586ae0606650229e87d75d Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 3 Aug 2021 04:44:14 -0400 Subject: silhouettes contact endpoint --- lib/mail.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/mail.js b/lib/mail.js index 9780fab7..ca2c2b81 100644 --- a/lib/mail.js +++ b/lib/mail.js @@ -10,6 +10,22 @@ function openInbox(cb) { imap.openBox("INBOX", true, cb); } +app.post( + "/contact-sil", + ah((req, res) => { + const mailgun = require("mailgun-js")(config.mailgun); + let data = { + subject: "Contact form", + text: JSON.stringify(req.body), + from: "server@coinos.io", + to: "testsil@coinos.io" + }; + + mailgun.messages().send(data); + res.send(req.body); + }) +); + app.post( "/contact", ah((req, res) => { -- cgit v1.2.3 From 05f4be452167da0ee719b6d27b16299c189a748c Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 3 Aug 2021 04:44:52 -0400 Subject: increase allowed fee rate --- lib/send.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/send.js b/lib/send.js index 660fcae4..fd577231 100644 --- a/lib/send.js +++ b/lib/send.js @@ -6,7 +6,7 @@ send = async (amount, memo, hash, user) => { let routingInfo = payreq.tags.find(t => t.tagName === "routing_info"); if ( routingInfo && - routingInfo.data.find(d => d.fee_proportional_millionths > 100) + routingInfo.data.find(d => d.fee_proportional_millionths > 1000) ) throw new Error("Fee rate too high"); -- cgit v1.2.3 From 1fbae57bb9540b1c116efc367809ac01ae2e9df2 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 3 Aug 2021 04:47:20 -0400 Subject: move lightning invoice fetch out of db transaction --- routes/lightning/receive.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js index 55193d2d..492320d3 100644 --- a/routes/lightning/receive.js +++ b/routes/lightning/receive.js @@ -1,20 +1,18 @@ const handlePayment = async msg => { + if (!msg.settled) return; let account, total, user; - try { - await db.transaction(async transaction => { - if (!msg.settled) return; - const invoice = await db.Invoice.findOne({ - where: { - text: msg.payment_request - } - }); + const invoice = await db.Invoice.findOne({ + where: { + text: msg.payment_request + } + }); - if (!invoice) - return l.warn( - "received lightning with no invoice", - msg.payment_request - ); + if (!invoice) + return l.warn("received lightning with no invoice", msg.payment_request); + + try { + await db.transaction(async transaction => { const { text: hash, currency, memo, rate, tip, user_id } = invoice; const amount = parseInt(msg.amt_paid_sat) - tip; @@ -83,7 +81,12 @@ const handlePayment = async msg => { let c = convert[msg.payment_request]; if (msg.payment_request && c) { - l.info("lightning detected for conversion request", msg.payment_request, c.address, user.username); + l.info( + "lightning detected for conversion request", + msg.payment_request, + c.address, + user.username + ); user.account = account; -- cgit v1.2.3 From c6ff23c0c5174ae2ac7f33fdd2b952bbe50750da Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 3 Aug 2021 02:16:30 -0700 Subject: re-enable lnd support --- lib/lnd.js | 36 ++++++++++++++++++++++++++++++++++++ package.json | 1 + routes/payments.js | 2 +- yarn.lock | 14 +++++++++++++- 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 lib/lnd.js diff --git a/lib/lnd.js b/lib/lnd.js new file mode 100644 index 00000000..c6caf3be --- /dev/null +++ b/lib/lnd.js @@ -0,0 +1,36 @@ +const fs = require('fs'); +const path = require('path'); +const grpc = require('@grpc/grpc-js'); +const protoLoader = require('@grpc/proto-loader'); +const { promisify } = require('util'); + + +module.exports = ({ tls, macaroon, server }) => { + const packageDefinition = protoLoader.loadSync('config/rpc.proto', { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true + }); + const lnrpc = grpc.loadPackageDefinition(packageDefinition).lnrpc; + process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA' + const lndCert = fs.readFileSync(tls); + const sslCreds = grpc.credentials.createSsl(lndCert); + const macaroonCreds = grpc.credentials.createFromMetadataGenerator(function(args, callback) { + const macaroonFile = fs.readFileSync(macaroon).toString('hex'); + const metadata = new grpc.Metadata() + metadata.add('macaroon', macaroonFile); + callback(null, metadata); + }); + const creds = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds); + const lnd = new lnrpc.Lightning(server, creds); + + return new Proxy(lnd, { + get(target, key) { + const method = target[key]; + if (typeof method === 'function' && !key.startsWith('sub')) return promisify(method); + return target[key]; + }, + }); +} diff --git a/package.json b/package.json index a62f37cf..a85e9867 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "@asoltys/bitcoin-core": "^3.0.7", "@asoltys/liquidjs-lib": "^5.1.38", + "@grpc/grpc-js": "^1.3.6", "@grpc/proto-loader": "^0.5.3", "async-mutex": "^0.2.4", "axios": "^0.21.1", diff --git a/routes/payments.js b/routes/payments.js index e78730d2..b12ae978 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -96,7 +96,7 @@ ah(async () => { if (config.lna.clightning) { lna = require("clightning-client")(config.lna.dir); } else { - throw new Error("lnd not supported"); + lna = lnd(config.lna); } app.post("/lightning/channel", require("./lightning/channel")); diff --git a/yarn.lock b/yarn.lock index d8cfa79c..ebe8c6f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -70,6 +70,13 @@ "@types/node" "^13.9.2" long "^4.0.0" +"@grpc/grpc-js@^1.3.6": + version "1.3.6" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.3.6.tgz#6e2d17610c2c8df0f6ceab0e1968f563df74b173" + integrity sha512-v7+LQFbqZKmd/Tvf5/j1Xlbq6jXL/4d+gUtm2TNX4QiEC3ELWADmGr2dGlUyLl6aKTuYfsN72vAsO5zmavYkEg== + dependencies: + "@types/node" ">=12.12.47" + "@grpc/proto-loader@^0.5.3": version "0.5.6" resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.6.tgz#1dea4b8a6412b05e2d58514d507137b63a52a98d" @@ -320,6 +327,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== +"@types/node@>=12.12.47": + version "16.4.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.10.tgz#e57e2a54fc6da58da94b3571b1cb456d39f88597" + integrity sha512-TmVHsm43br64js9BqHWqiDZA+xMtbUpI1MBIA0EyiBmoV9pcEYFOSdj5fr6enZNfh4fChh+AGOLIzGwJnkshyQ== + "@types/node@^13.9.2": version "13.13.52" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.52.tgz#03c13be70b9031baaed79481c0c0cfb0045e53f7" @@ -644,7 +656,7 @@ bip174@^2.0.1: resolved "https://registry.yarnpkg.com/bip174/-/bip174-2.0.1.tgz#39cf8ca99e50ce538fb762589832f4481d07c254" integrity sha512-i3X26uKJOkDTAalYAp0Er+qGMDhrbbh2o93/xiPyAN2s25KrClSpe3VXo/7mNJoqA5qfko8rLS2l3RWZgYmjKQ== -"bip174@github:vulpemventures/bip174": +bip174@vulpemventures/bip174.git: version "1.0.3" resolved "https://codeload.github.com/vulpemventures/bip174/tar.gz/b6d0ffe54e0dfa72e971b68372f89b25f7602502" -- cgit v1.2.3 From 8b06e5a742a529e98736a2b60dc3b2f5d581fe03 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 4 Aug 2021 07:00:20 -0700 Subject: config update, lnd support --- docker-compose.dev.yml | 51 +++++ docker-compose.yml | 67 ++----- lib/lnd.js | 44 +---- lib/send.js | 2 +- package.json | 5 +- routes/assets.js | 1 - routes/info.js | 6 +- routes/lightning/channel.js | 4 +- routes/lightning/invoice.js | 5 +- routes/lightning/send.js | 2 +- routes/liquid/send.js | 2 +- routes/lnurl.js | 8 +- routes/payments.js | 71 ++++--- sampleconfig/bitcoin/bitcoin.conf | 4 +- sampleconfig/index.js | 8 +- sampleconfig/lightningb/config | 7 - sampleconfig/liquid/elements.conf | 10 +- sampleconfig/lnd/lnd.conf | 20 ++ yarn.lock | 405 ++++++++++++++++++++++++++++++++------ 19 files changed, 503 insertions(+), 219 deletions(-) delete mode 100644 sampleconfig/lightningb/config create mode 100644 sampleconfig/lnd/lnd.conf diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index c40a3ef1..11a41e64 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -11,3 +11,54 @@ services: NODE_ENV: development volumes: - ../coinos-ui:/coinos-ui + electrs-liquid: + image: vulpemventures/electrs-liquid:latest + container_name: electrs + depends_on: + - liquid + entrypoint: + - /build/electrs + command: + - -vvvv + - --parent-network + - regtest + - --network + - liquidregtest + - --daemon-dir + - /config + - --daemon-rpc-addr + - liquid:7040 + - --cookie + - admin1:123 + - --http-addr + - 0.0.0.0:3002 + - --electrum-rpc-addr + - 0.0.0.0:60401 + - --cors + - "*" + ports: + - ${LIQUID_ELECTRS_RPC_PORT}:60401 + - ${LIQUID_ELECTRS_PORT}:3002 + volumes: + - ./config/liquid/:/config + restart: unless-stopped + esplora-liquid: + image: vulpemventures/esplora:latest + container_name: esplora-liquid + depends_on: + - electrs-liquid + environment: + API_URL: ${LIQUID_ELECTRS_URL} + NATIVE_ASSET_ID: 5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225 + IS_ELEMENTS: 1 + ports: + - ${LIQUID_ESPLORA_PORT}:5000 + restart: unless-stopped + clightning: + image: elementsproject/lightningd:latest + container_name: cl + environment: + LIGHTNINGD_NETWORK: regtest + volumes: + - ./config/lightning:/root/.lightning + restart: unless-stopped diff --git a/docker-compose.yml b/docker-compose.yml index febdba4f..c86ba2d1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,11 @@ version: '3.6' services: app: + depends_on: + - maria + - bitcoin + - liquid + - lnd container_name: app image: asoltys/coinos-server ports: @@ -25,65 +30,17 @@ services: ports: - ${LIQUID_NODE_PORT}:7040 - ${LIQUID_PEER_PORT}:18444 - - ${LIQUID_BLOCK_PORT}:18602 - - ${LIQUID_TX_PORT}:18603 + - ${LIQUID_BLOCK_PORT}:18606 + - ${LIQUID_TX_PORT}:18607 volumes: - ./config/liquid:/config restart: unless-stopped - la: - image: elementsproject/lightningd:latest - container_name: la - environment: - LIGHTNINGD_NETWORK: regtest - volumes: - - ./config/lightning:/root/.lightning - restart: unless-stopped - lb: - image: elementsproject/lightningd:latest - container_name: lb - environment: - LIGHTNINGD_NETWORK: regtest - volumes: - - ./config/lightningb:/root/.lightning - restart: unless-stopped - electrs-liquid: - image: vulpemventures/electrs-liquid:latest - container_name: electrs-liquid - entrypoint: - - /build/electrs - command: - - -vvvv - - --parent-network - - regtest - - --network - - liquidregtest - - --daemon-dir - - /config - - --daemon-rpc-addr - - liquid:7040 - - --cookie - - admin1:123 - - --http-addr - - 0.0.0.0:3002 - - --electrum-rpc-addr - - 0.0.0.0:60401 - - --cors - - "*" - ports: - - ${LIQUID_ELECTRS_RPC_PORT}:60401 - - ${LIQUID_ELECTRS_PORT}:3002 + lnd: + image: lnd + container_name: lnd volumes: - - ./liquid/:/config - restart: unless-stopped - esplora-liquid: - image: vulpemventures/esplora:latest - container_name: esplora-liquid - environment: - API_URL: ${LIQUID_ELECTRS_URL} - NATIVE_ASSET_ID: 5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225 - IS_ELEMENTS: 1 - ports: - - ${LIQUID_ESPLORA_PORT}:5000 + - ./config/lnd:/root/.lnd + - ./config/bitcoin:/root/.bitcoin restart: unless-stopped maria: container_name: mariadb diff --git a/lib/lnd.js b/lib/lnd.js index c6caf3be..b31933a5 100644 --- a/lib/lnd.js +++ b/lib/lnd.js @@ -1,36 +1,12 @@ -const fs = require('fs'); -const path = require('path'); -const grpc = require('@grpc/grpc-js'); -const protoLoader = require('@grpc/proto-loader'); -const { promisify } = require('util'); +const { promisify } = require("util"); +const { authenticatedLndGrpc } = require("lightning"); +const { cert, macaroon, socket } = config.lna; -module.exports = ({ tls, macaroon, server }) => { - const packageDefinition = protoLoader.loadSync('config/rpc.proto', { - keepCase: true, - longs: String, - enums: String, - defaults: true, - oneofs: true - }); - const lnrpc = grpc.loadPackageDefinition(packageDefinition).lnrpc; - process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA' - const lndCert = fs.readFileSync(tls); - const sslCreds = grpc.credentials.createSsl(lndCert); - const macaroonCreds = grpc.credentials.createFromMetadataGenerator(function(args, callback) { - const macaroonFile = fs.readFileSync(macaroon).toString('hex'); - const metadata = new grpc.Metadata() - metadata.add('macaroon', macaroonFile); - callback(null, metadata); - }); - const creds = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds); - const lnd = new lnrpc.Lightning(server, creds); - - return new Proxy(lnd, { - get(target, key) { - const method = target[key]; - if (typeof method === 'function' && !key.startsWith('sub')) return promisify(method); - return target[key]; - }, - }); -} +const { lnd } = authenticatedLndGrpc({ + cert, + macaroon, + socket +}); + +module.exports = lnd diff --git a/lib/send.js b/lib/send.js index fd577231..92b2eda3 100644 --- a/lib/send.js +++ b/lib/send.js @@ -52,7 +52,7 @@ send = async (amount, memo, hash, user) => { fee = parseInt((sent - total) / 1000); total = parseInt(total / 1000); } else { - let m = await lna.sendPaymentSync({ + let m = await lnp.sendPaymentSync({ amt: amount, payment_request: hash, max_parts: 10, diff --git a/package.json b/package.json index a85e9867..f4db1af1 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,6 @@ "dependencies": { "@asoltys/bitcoin-core": "^3.0.7", "@asoltys/liquidjs-lib": "^5.1.38", - "@grpc/grpc-js": "^1.3.6", - "@grpc/proto-loader": "^0.5.3", "async-mutex": "^0.2.4", "axios": "^0.21.1", "bcrypt": "^5.0.0", @@ -20,7 +18,7 @@ "bip39": "^3.0.2", "bitcoinjs-lib": "^5.1.8", "body-parser": "^1.19.0", - "bolt11": "^1.2.5", + "bolt11": "^1.3.2", "buffer-reverse": "^1.0.1", "clightning-client": "^0.1.2", "coinselect": "^3.1.12", @@ -35,6 +33,7 @@ "imap": "^0.8.19", "jsonwebtoken": "^8.5.1", "knex": "^0.95.6", + "lightning": "^3.5.0", "lnurl": "^0.16.1", "long": "^4.0.0", "mailgun-js": "^0.22.0", diff --git a/routes/assets.js b/routes/assets.js index 3f483a28..fe667dd9 100644 --- a/routes/assets.js +++ b/routes/assets.js @@ -148,7 +148,6 @@ app.post( const brt = await lq.blindRawTransaction(hex, true, [], false); const srt = await lq.signRawTransactionWithWallet(brt); const allowed = (await lq.testMempoolAccept([srt.hex]))[0].allowed; - fs.writeFileSync('tx', srt.hex); if (!allowed) throw new Error("issuance rejected by mempool"); const txid = await lq.sendRawTransaction(srt.hex); diff --git a/routes/info.js b/routes/info.js index f8a0fa72..6d9d5f32 100644 --- a/routes/info.js +++ b/routes/info.js @@ -34,9 +34,9 @@ app.get("/balances", ah(async (req, res, next) => { lnchannel = parseInt(funds.channels.reduce((a, b) => a + b.channel_sat, 0)); lnwallet = parseInt(funds.outputs.reduce((a, b) => a + b.value, 0)); } else { - lninfo = await lna.getInfo({}); - lnchannel = parseInt((await lna.channelBalance({})).balance); - lnwallet = parseInt((await lna.walletBalance({})).total_balance); + lninfo = await lnp.getInfo({}); + lnchannel = parseInt((await lnp.channelBalance({})).balance); + lnwallet = parseInt((await lnp.walletBalance({})).total_balance); } } diff --git a/routes/lightning/channel.js b/routes/lightning/channel.js index b6c4a25f..cb8ddf07 100644 --- a/routes/lightning/channel.js +++ b/routes/lightning/channel.js @@ -7,7 +7,7 @@ module.exports = ah(async (req, res) => { l.info("connecting to peer", req.user.username, pubkey, host); let result; try { - result = await lna.connectPeer({ + result = await lnp.connectPeer({ addr: { pubkey, host }, perm: true }); @@ -21,7 +21,7 @@ module.exports = ah(async (req, res) => { const { callback, k1 } = params; let remoteid; try { - remoteid = (await lna.getInfo({})).identity_pubkey; + remoteid = (await lnp.getInfo({})).identity_pubkey; } catch(e) { l.error("problem getting lightning node info", e.message); return res.status(500).send(e.message); diff --git a/routes/lightning/invoice.js b/routes/lightning/invoice.js index 1f3a0528..054a4a46 100644 --- a/routes/lightning/invoice.js +++ b/routes/lightning/invoice.js @@ -1,3 +1,4 @@ + module.exports = ah(async (req, res) => { let { amount, memo, tip } = req.body; if (!tip) tip = 0; @@ -14,11 +15,11 @@ module.exports = ah(async (req, res) => { ); res.send(invoice.bolt11); } else { - const invoice = await lna.addInvoice({ value, memo }); + const invoice = await lnp.addInvoice({ value, memo }); res.send(invoice.payment_request); } } catch (e) { - l.error("problem creating invoice", e.message); + l.error("problem creating invoice", e.message, e.stack); res.status(500).send(e.message); } }); diff --git a/routes/lightning/send.js b/routes/lightning/send.js index f6bd1b36..f3c0da46 100644 --- a/routes/lightning/send.js +++ b/routes/lightning/send.js @@ -5,7 +5,7 @@ module.exports = ah(async (req, res) => { try { res.send(await send(amount, memo, payreq, user)); } catch (e) { - l.error("problem sending lightning payment", user.username, e.message); + l.error("problem sending lightning payment", user.username, e.message, e.stack); res.status(500).send(e.message); } }); diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 13f77d26..5abc692f 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -1,6 +1,6 @@ const btc = config.liquid.btcasset; const lcad = config.liquid.cadasset; -const { Transaction } = require("liquidjs-lib"); +const { Transaction } = require("@asoltys/liquidjs-lib"); sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { if (amount > 10000000) throw new Error("Amount too large"); diff --git a/routes/lnurl.js b/routes/lnurl.js index f6b066ff..adf4df7c 100644 --- a/routes/lnurl.js +++ b/routes/lnurl.js @@ -90,7 +90,7 @@ app.post( amount: value, params: { callback, k1 } } = req.body; - const invoice = await lna.addInvoice({ value }); + const invoice = await lnp.addInvoice({ value }); const { payment_request: pr } = invoice; const url = `${callback}?k1=${k1}&pr=${pr}`; @@ -284,7 +284,7 @@ lnurlServer.bindToHook( if (recipient) { setTimeout(async () => { - let { invoices } = await lna.listInvoices({ + let { invoices } = await lnp.listInvoices({ pending_only: true }); @@ -352,7 +352,7 @@ lnurlServer.bindToHook( } try { - let decoded = await lna.decodePayReq({ pay_req: pr }); + let decoded = await lnp.decodePayReq({ pay_req: pr }); let amount = decoded.num_satoshis; await db.transaction(async transaction => { @@ -385,7 +385,7 @@ lnurlServer.bindToHook( setTimeout(async () => { try { - let { payments } = await lna.listPayments({ + let { payments } = await lnp.listPayments({ include_incomplete: false, max_payments: 5, reversed: true diff --git a/routes/payments.js b/routes/payments.js index b12ae978..70b711da 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -2,6 +2,7 @@ const BitcoinCore = require("@asoltys/bitcoin-core"); const { Op } = require("sequelize"); const { join } = require("path"); const fs = require("fs"); +const lnd = require("../lib/lnd"); const read = require("../lib/read"); ah(async () => { @@ -12,34 +13,34 @@ ah(async () => { const exceptions = []; try { - read(fs.createReadStream("exceptions"), (data) => exceptions.push(data)); + read(fs.createReadStream("exceptions"), data => exceptions.push(data)); } catch (e) { l.warn("couldn't read exceptions file", e.message); } try { - ( - await db.Invoice.findAll({ - include: { - model: db.User, - as: "user", - }, - }) - ).map(({ address, user, unconfidential }) => { - if (address && user) addresses[address] = user.username; - if (unconfidential && user) addresses[unconfidential] = user.username; - }); - } catch(e) { + ( + await db.Invoice.findAll({ + include: { + model: db.User, + as: "user" + } + }) + ).map(({ address, user, unconfidential }) => { + if (address && user) addresses[address] = user.username; + if (unconfidential && user) addresses[unconfidential] = user.username; + }); + } catch (e) { console.log(e); - } + } try { const accounts = await db.Account.findAll({ where: { pubkey: { [Op.ne]: null } }, include: { model: db.User, - as: "user", - }, + as: "user" + } }); accounts.map(({ address, user: { username } }) => { @@ -51,36 +52,35 @@ ah(async () => { payments = ( await db.Payment.findAll({ - attributes: ["hash"], + attributes: ["hash"] }) - ).map((p) => p.hash); - + ).map(p => p.hash); setInterval(async () => { const unconfirmed = ( await db.Payment.findAll({ where: { - confirmed: 0, - }, + confirmed: 0 + } }) - ).map((p) => p.hash); + ).map(p => p.hash); const transactions = await bc.listTransactions("*", 1000); transactions .filter( - (tx) => + tx => tx.category === "receive" && tx.confirmations > 0 && unconfirmed.includes(tx.txid) ) - .map((tx) => { + .map(tx => { l.warn("tx unconfirmed in db", tx.txid, tx.address); }); const unaccounted = []; - transactions.map((tx) => { + transactions.map(tx => { if (!payments.includes(tx.txid) && !exceptions.includes(tx.txid)) { unaccounted.push(tx.txid); } @@ -96,7 +96,22 @@ ah(async () => { if (config.lna.clightning) { lna = require("clightning-client")(config.lna.dir); } else { - lna = lnd(config.lna); + lna = lnd.default; + lnp = [ + "addInvoice", + "channelBalance", + "connectPeer", + "decodePayReq", + "getInfo", + "listInvoices", + "listPayments", + "sendPaymentSync", + "walletBalance" + ].reduce( + (a, b) => + (a[b] = args => new Promise(r => lna[b](args, (e, v) => r(v)))) && a, + {} + ); } app.post("/lightning/channel", require("./lightning/channel")); @@ -151,9 +166,9 @@ ah(async () => { const { hdkeypath } = await lq.getAddressInfo(address); const parts = hdkeypath.split("/"); app.set("lqAddressIndex", parts[parts.length - 1].slice(0, -1)); - } catch(e) { + } catch (e) { l.warn("Problem getting liquid address index", e.message); - } + } }, 50); } diff --git a/sampleconfig/bitcoin/bitcoin.conf b/sampleconfig/bitcoin/bitcoin.conf index 90b838d8..16ff8e91 100644 --- a/sampleconfig/bitcoin/bitcoin.conf +++ b/sampleconfig/bitcoin/bitcoin.conf @@ -12,9 +12,9 @@ rpcuser=admin1 rpcpassword=123 rpcallowip=0.0.0.0/0 rpcbind=0.0.0.0 +rpcwallet=coinos -wallet= -wallet=coinosdev +wallet=coinos zmqpubrawblock=tcp://0.0.0.0:18506 zmqpubrawtx=tcp://0.0.0.0:18507 diff --git a/sampleconfig/index.js b/sampleconfig/index.js index 6dc1bda5..84b4c632 100644 --- a/sampleconfig/index.js +++ b/sampleconfig/index.js @@ -25,7 +25,7 @@ module.exports = { masterkey: "tprv8ZgxMBicQKsPdTUoagV41nang9pQUA2DKoVWLmTrWmb2PfsC8pDTHveCMyzUyMguKJCjd5uyHcqg27r7gDzz4TY3MgucpLsSXwCbjn2C3Q1", host: "bitcoin", - wallet: "coinosdev", + wallet: "coinos", username: "admin1", password: "123", network: "regtest", @@ -42,10 +42,10 @@ module.exports = { username: "admin1", password: "123", network: "regtest", - wallet: "a", + wallet: "coinos", port: 7040, - zmqrawblock: "tcp://liquid:18602", - zmqrawtx: "tcp://liquid:18603", + zmqrawblock: "tcp://liquid:18606", + zmqrawtx: "tcp://liquid:18607", btcasset, }, lna: { diff --git a/sampleconfig/lightningb/config b/sampleconfig/lightningb/config deleted file mode 100644 index 14e913c3..00000000 --- a/sampleconfig/lightningb/config +++ /dev/null @@ -1,7 +0,0 @@ -alias=coinos -rgb=006000 -bitcoin-rpcconnect=bitcoin -bitcoin-rpcport=18443 -bitcoin-rpcuser=admin1 -bitcoin-rpcpassword=123 -network=regtest diff --git a/sampleconfig/liquid/elements.conf b/sampleconfig/liquid/elements.conf index ce93b307..08b60dd6 100644 --- a/sampleconfig/liquid/elements.conf +++ b/sampleconfig/liquid/elements.conf @@ -7,13 +7,11 @@ rpcuser=admin1 rpcpassword=123 rpcbind=0.0.0.0 rpcallowip=0.0.0.0/0 -rpcwallet=a +rpcwallet=coinos validatepegin=0 initialfreecoins=2100000000000000 -wallet= -wallet=a -wallet=b +wallet=coinos -zmqpubrawblock=tcp://0.0.0.0:18602 -zmqpubrawtx=tcp://0.0.0.0:18603 +zmqpubrawblock=tcp://0.0.0.0:18606 +zmqpubrawtx=tcp://0.0.0.0:18607 diff --git a/sampleconfig/lnd/lnd.conf b/sampleconfig/lnd/lnd.conf new file mode 100644 index 00000000..f0e12830 --- /dev/null +++ b/sampleconfig/lnd/lnd.conf @@ -0,0 +1,20 @@ +externalip=lnd:9735 +alias=coinos +color=#FF3200 +tlsextradomain=lnd +listen=0.0.0.0:9735 +rpclisten=0.0.0.0:10009 +restlisten=0.0.0.0:8080 + +[Bitcoin] +bitcoin.active=1 +bitcoin.node=bitcoind +bitcoin.regtest=1 + +[Bitcoind] +bitcoind.rpchost=bitcoin +bitcoind.dir=/root/.bitcoin +bitcoind.rpcuser=admin1 +bitcoind.rpcpass=123 +bitcoind.zmqpubrawblock=tcp://bitcoin:18506 +bitcoind.zmqpubrawtx=tcp://bitcoin:18507 diff --git a/yarn.lock b/yarn.lock index ebe8c6f2..5c526c30 100644 --- a/yarn.lock +++ b/yarn.lock @@ -70,20 +70,28 @@ "@types/node" "^13.9.2" long "^4.0.0" -"@grpc/grpc-js@^1.3.6": +"@cto.af/textdecoder@^0.0.0": + version "0.0.0" + resolved "https://registry.yarnpkg.com/@cto.af/textdecoder/-/textdecoder-0.0.0.tgz#e1e8d84c936c30a0f4619971f19ca41941af9fdc" + integrity sha512-sJpx3F5xcVV/9jNYJQtvimo4Vfld/nD3ph+ZWtQzZ03Zo8rJC7QKQTRcIGS13Rcz80DwFNthCWMrd58vpY4ZAQ== + +"@grpc/grpc-js@1.3.6": version "1.3.6" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.3.6.tgz#6e2d17610c2c8df0f6ceab0e1968f563df74b173" integrity sha512-v7+LQFbqZKmd/Tvf5/j1Xlbq6jXL/4d+gUtm2TNX4QiEC3ELWADmGr2dGlUyLl6aKTuYfsN72vAsO5zmavYkEg== dependencies: "@types/node" ">=12.12.47" -"@grpc/proto-loader@^0.5.3": - version "0.5.6" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.6.tgz#1dea4b8a6412b05e2d58514d507137b63a52a98d" - integrity sha512-DT14xgw3PSzPxwS13auTEwxhMMOoz33DPUKNtmYK/QYbBSpLXJy78FGGs5yVoxVobEqPm4iW9MOIoz0A3bLTRQ== +"@grpc/proto-loader@0.6.4": + version "0.6.4" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.4.tgz#5438c0d771e92274e77e631babdc14456441cbdc" + integrity sha512-7xvDvW/vJEcmLUltCUGOgWRPM8Oofv0eCFSVMuKqaqWJaXSzmB+m9hiyqe34QofAl4WAzIKUZZlinIF9FOHyTQ== dependencies: + "@types/long" "^4.0.1" lodash.camelcase "^4.3.0" - protobufjs "^6.8.6" + long "^4.0.0" + protobufjs "^6.10.0" + yargs "^16.1.1" "@hapi/bourne@^2.0.0": version "2.0.0" @@ -173,23 +181,24 @@ "@otplib/plugin-crypto" "^12.0.1" "@otplib/plugin-thirty-two" "^12.0.1" -"@pm2/agent@~1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@pm2/agent/-/agent-1.0.8.tgz#cd15d84dbfc95427e6fccce72bc165b79f1d8579" - integrity sha512-r8mud8BhBz+a2yjlgtk+PBXUR5EQ9UKSJCs232OxfCmuBr1MZw0Mo+Kfog6WJ8OmVk99r1so9yTUK4IyrgGcMQ== +"@pm2/agent@~2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@pm2/agent/-/agent-2.0.0.tgz#b3ab77cd12d85187dd155c59a9771b04e7e345a3" + integrity sha512-W1LvdyF1tGaVU5f/hV8DjpI5joI7MEgXiQMLZnTwZlFwDVP00O9s86571Q8xSiweTcFZFyye0F4wORN/PjSgGA== dependencies: async "~3.2.0" chalk "~3.0.0" dayjs "~1.8.24" debug "~4.3.1" eventemitter2 "~5.0.1" + fast-json-patch "^3.0.0-1" fclone "~1.0.11" nssocket "0.6.0" pm2-axon "~4.0.1" pm2-axon-rpc "~0.7.0" proxy-agent "~4.0.1" semver "~7.2.0" - ws "~7.2.0" + ws "~7.4.0" "@pm2/io@~5.0.0": version "5.0.0" @@ -302,6 +311,45 @@ dependencies: "@types/node" "*" +"@types/body-parser@*": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c" + integrity sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/caseless@*": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" + integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@^4.17.18": + version "4.17.24" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07" + integrity sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@4.17.13": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" + integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/geojson@^7946.0.7": version "7946.0.7" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.7.tgz#c8fa532b60a0042219cdf173ca21a975ef0666ad" @@ -312,6 +360,11 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + "@types/node@*", "@types/node@>=13.7.0": version "15.6.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-15.6.1.tgz#32d43390d5c62c5b6ec486a9bc9c59544de39a08" @@ -327,6 +380,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.6.tgz#df929d1bb2eee5afdda598a41930fe50b43eaa6a" integrity sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ== +"@types/node@16.4.3": + version "16.4.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.3.tgz#c01c1a215721f6dec71b47d88b4687463601ba48" + integrity sha512-GKM4FLMkWDc0sfx7tXqPWkM6NBow1kge0fgQh0bOnlqo4iT1kvTvMEKE0c1RtUGnbLlGRXiAA8SumE//90uKAg== + "@types/node@>=12.12.47": version "16.4.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.10.tgz#e57e2a54fc6da58da94b3571b1cb456d39f88597" @@ -342,6 +400,46 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.1.tgz#5e07e0cb2ff793aa7a1b41deae76221e6166049f" integrity sha512-/tpUyFD7meeooTRwl3sYlihx2BrJE7q9XF71EguPFIySj9B7qgnRtHsHTho+0AUm4m1SvWGm6uSncrR94q6Vtw== +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/request@2.48.6": + version "2.48.6" + resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.6.tgz#2300e7fc443108f79efa90e3bdf34c6d60fa89d8" + integrity sha512-vrZaV3Ij7j/l/3hz6OttZFtpRCu7zlq7XgkYHJP6FwVEAZkGQ095WqyJV08/GlW9eyXKVcp/xmtruHm8eHpw1g== + dependencies: + "@types/caseless" "*" + "@types/node" "*" + "@types/tough-cookie" "*" + form-data "^2.5.0" + +"@types/serve-static@*": + version "1.13.10" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" + integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/tough-cookie@*": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.1.tgz#8f80dd965ad81f3e1bc26d6f5c727e132721ff40" + integrity sha512-Y0K95ThC3esLEYD6ZuqNek29lNX2EM1qxV8y2FTLUB0ff5wWrk7az+mLrnNFUnaXcgKye22+sFBRXOgpPILZNg== + +"@types/ws@7.4.7": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -437,7 +535,7 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -548,7 +646,7 @@ async-mutex@^0.2.4: dependencies: tslib "^2.0.0" -async@3.2.0, async@~3.2.0: +async@3.2.0, async@^3.2.0, async@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== @@ -560,6 +658,13 @@ async@^2.6.1, async@^2.6.3, async@~2.6.1: dependencies: lodash "^4.17.14" +asyncjs-util@1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/asyncjs-util/-/asyncjs-util-1.2.6.tgz#fafb5dd8b36c8ac37db38ce9b1c36ea2941b101a" + integrity sha512-PxQ2drzeOUe20HsjIXOlfw76Ci8RQkF2B95arcQap02jJ3lByNKkC3MtVFhIWF+FYl738tD/tZHOlUuYfamFvw== + dependencies: + async "3.2.0" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -683,56 +788,56 @@ bip39@^3.0.2: pbkdf2 "^3.0.9" randombytes "^2.0.1" -bip66@^1.1.0, bip66@^1.1.5: +bip66@1.1.5, bip66@^1.1.0, bip66@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" integrity sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI= dependencies: safe-buffer "^5.0.1" -bitcoin-ops@^1.3.0, bitcoin-ops@^1.4.0: +bitcoin-ops@1.4.1, bitcoin-ops@^1.3.0, bitcoin-ops@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz#e45de620398e22fd4ca6023de43974ff42240278" integrity sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow== -bitcoinjs-lib@^3.3.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/bitcoinjs-lib/-/bitcoinjs-lib-3.3.2.tgz#780c9c53ecb1222adb463b58bef26386067b609a" - integrity sha512-l5qqvbaK8wwtANPf6oEffykycg4383XgEYdia1rI7/JpGf1jfRWlOUCvx5TiTZS7kyIvY4j/UhIQ2urLsvGkzw== +bitcoinjs-lib@5.2.0, bitcoinjs-lib@^5.1.8: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bitcoinjs-lib/-/bitcoinjs-lib-5.2.0.tgz#caf8b5efb04274ded1b67e0706960b93afb9d332" + integrity sha512-5DcLxGUDejgNBYcieMIUfjORtUeNWl828VWLHJGVKZCb4zIS1oOySTUr0LGmcqJBQgTBz3bGbRQla4FgrdQEIQ== dependencies: bech32 "^1.1.2" - bigi "^1.4.0" + bip174 "^2.0.1" + bip32 "^2.0.4" bip66 "^1.1.0" - bitcoin-ops "^1.3.0" + bitcoin-ops "^1.4.0" bs58check "^2.0.0" create-hash "^1.1.0" create-hmac "^1.1.3" - ecurve "^1.0.0" merkle-lib "^2.0.10" pushdata-bitcoin "^1.0.1" randombytes "^2.0.1" - safe-buffer "^5.0.1" + tiny-secp256k1 "^1.1.1" typeforce "^1.11.3" varuint-bitcoin "^1.0.4" wif "^2.0.1" -bitcoinjs-lib@^5.1.8: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bitcoinjs-lib/-/bitcoinjs-lib-5.2.0.tgz#caf8b5efb04274ded1b67e0706960b93afb9d332" - integrity sha512-5DcLxGUDejgNBYcieMIUfjORtUeNWl828VWLHJGVKZCb4zIS1oOySTUr0LGmcqJBQgTBz3bGbRQla4FgrdQEIQ== +bitcoinjs-lib@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/bitcoinjs-lib/-/bitcoinjs-lib-3.3.2.tgz#780c9c53ecb1222adb463b58bef26386067b609a" + integrity sha512-l5qqvbaK8wwtANPf6oEffykycg4383XgEYdia1rI7/JpGf1jfRWlOUCvx5TiTZS7kyIvY4j/UhIQ2urLsvGkzw== dependencies: bech32 "^1.1.2" - bip174 "^2.0.1" - bip32 "^2.0.4" + bigi "^1.4.0" bip66 "^1.1.0" - bitcoin-ops "^1.4.0" + bitcoin-ops "^1.3.0" bs58check "^2.0.0" create-hash "^1.1.0" create-hmac "^1.1.3" + ecurve "^1.0.0" merkle-lib "^2.0.10" pushdata-bitcoin "^1.0.1" randombytes "^2.0.1" - tiny-secp256k1 "^1.1.1" + safe-buffer "^5.0.1" typeforce "^1.11.3" varuint-bitcoin "^1.0.4" wif "^2.0.1" @@ -754,6 +859,11 @@ bluebird@^3.5.0: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +bn.js@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + bn.js@^4.0.0, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" @@ -780,7 +890,19 @@ body-parser@1.19.0, body-parser@^1.19.0: raw-body "2.4.0" type-is "~1.6.17" -bolt11@1.3.1, bolt11@^1.2.5: +bolt07@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/bolt07/-/bolt07-1.7.3.tgz#e46b44a9051ad4999fc867023dc6270f04013e66" + integrity sha512-zXhf60qEpFXwRTeoaJ+0SyPw/jzBtIHZLCJBvaa0rFGiiQKdWXdaiIWeyIkxl74p/UGUv4BQsbkAgB0Em/1QOQ== + dependencies: + bn.js "5.2.0" + +bolt09@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/bolt09/-/bolt09-0.1.5.tgz#614ade121983b7efa3f86df7e3a30c84854012a7" + integrity sha512-oT1+erg21vat55oXNd7nNEkCO0FQnmaraFZuyXFyeVk7dZCm/3vgic0qK1VuUSV+ksYXJfRKYC4AqfYrtHNPZg== + +bolt11@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/bolt11/-/bolt11-1.3.1.tgz#583af1e3af1f0456be0ebeb0470af023ddfcde9b" integrity sha512-dmTcJGIQ4RcSDgXMijhUO4JWskCelXhbpcedWsF7YoFcPw3QYzYWCowO0+GJFT2TvrHXtlYdbnMBT85Se8IJSA== @@ -794,6 +916,25 @@ bolt11@1.3.1, bolt11@^1.2.5: safe-buffer "^5.1.1" secp256k1 "^3.4.0" +bolt11@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/bolt11/-/bolt11-1.3.2.tgz#7fc13ed7b1c86fab2e57927af057df55d7841b10" + integrity sha512-WW86n1QdusD6t3j64B+GZLztj4skwoH/LBiiIrt7zpQvtaGJsRMavv22tDwoDBF/Yb143omPIq+R6sJaRRUP9w== + dependencies: + "@types/bn.js" "^4.11.3" + bech32 "^1.1.2" + bitcoinjs-lib "^3.3.1" + bn.js "^4.11.8" + create-hash "^1.2.0" + lodash "^4.17.11" + safe-buffer "^5.1.1" + secp256k1 "^3.4.0" + +boolean@^3.0.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.1.2.tgz#e30f210a26b02458482a8cc353ab06f262a780c2" + integrity sha512-YN6UmV0FfLlBVvRvNPx3pz5W/mUoYB24J4WSXOKP/OOJpi+Oq6WYqPaNTHzjI0QzwWtnvEd5CGYyQPgp1jFxnw== + boxen@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" @@ -927,6 +1068,14 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +cbor@7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-7.0.6.tgz#ce47d1d5f946760f199f848dbbcfe762cf492fd6" + integrity sha512-rgt2RFogHGDLFU5r0kSfyeBc+de55DwYHP73KxKsQxsR5b0CYuQPH6AnJaXByiohpLdjQqj/K0SFcOV+dXdhSA== + dependencies: + "@cto.af/textdecoder" "^0.0.0" + nofilter "^2.0.3" + chalk@2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1015,6 +1164,15 @@ clightning-client@^0.1.2: debug "^4.1.1" error "^7.2.0" +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -1684,6 +1842,11 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-json-patch@^3.0.0-1: + version "3.0.0-1" + resolved "https://registry.yarnpkg.com/fast-json-patch/-/fast-json-patch-3.0.0-1.tgz#4c68f2e7acfbab6d29d1719c44be51899c93dabb" + integrity sha512-6pdFb07cknxvPzCeLsFHStEy+MysPJPgZQ9LbQ/2O67unQF93SNqfdSqnPPl71YMHX+AD8gbl7iuoGFzHEdDuw== + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -1694,6 +1857,13 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-printf@^1.3.0: + version "1.6.6" + resolved "https://registry.yarnpkg.com/fast-printf/-/fast-printf-1.6.6.tgz#7e9af8dabedf7a0b9760feae4d10b651d0d6a03b" + integrity sha512-Uz/uW6R1Fd8YqCGeoQosRIfB4dBbr8uMbFVdEci2AyXYcfucFqhpSMAGs8skRRdZd+MGCDBu48+B8Zmu7Pta5A== + dependencies: + boolean "^3.0.2" + fast-redact@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-2.1.0.tgz#dfe3c1ca69367fb226f110aa4ec10ec85462ffdf" @@ -1759,7 +1929,7 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= -form-data@^2.3.3: +form-data@^2.3.3, form-data@^2.5.0: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== @@ -1864,6 +2034,11 @@ generate-function@^2.3.1: dependencies: is-property "^1.0.2" +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -2220,6 +2395,18 @@ interpret@^2.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== +invoices@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invoices/-/invoices-2.0.0.tgz#f84185150720b7d7799bbe10dbb772c7fabf93d4" + integrity sha512-UnU0bS3+cMA2UvYrF5RXp/Hm7v/nYiA3F0GVCOeRmDiZmXAt/eO7KdqyRzewopvhBlev7F7t7GZzRRYY1XE3xg== + dependencies: + bech32 "2.0.0" + bitcoinjs-lib "5.2.0" + bn.js "5.2.0" + bolt07 "1.7.3" + bolt09 "0.1.5" + secp256k1 "4.0.2" + ip@1.1.5, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -2400,7 +2587,7 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= @@ -2523,6 +2710,29 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +lightning@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/lightning/-/lightning-3.5.0.tgz#757c41f5ea49e3ac7d17c8f4b68c7204c84ee6a6" + integrity sha512-6Kj1JX8tG3JiV5LXYGuZkKckiRJ/OU8ukb/R5qsp7RWq/xw32LDccCKvOK8oRnOGw9K+G8jcZAOY21exr9OSFA== + dependencies: + "@grpc/grpc-js" "1.3.6" + "@grpc/proto-loader" "0.6.4" + "@types/express" "4.17.13" + "@types/node" "16.4.3" + "@types/request" "2.48.6" + "@types/ws" "7.4.7" + async "3.2.0" + asyncjs-util "1.2.6" + bitcoinjs-lib "5.2.0" + bn.js "5.2.0" + body-parser "1.19.0" + bolt07 "1.7.3" + bolt09 "0.1.5" + cbor "7.0.6" + express "4.17.1" + invoices "2.0.0" + psbt "1.1.10" + lnurl@^0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/lnurl/-/lnurl-0.16.1.tgz#2bb8523f181ab8a8826e5b559be9e4cb183e0176" @@ -2983,6 +3193,13 @@ nodemon@^2.0.7: undefsafe "^2.0.3" update-notifier "^4.1.0" +nofilter@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-2.0.3.tgz#f5460f3cb33147005883e3f5d4476239501fa187" + integrity sha512-FbuXC+lK+GU2+63D1kC1ETiZo+Z7SIi7B+mxKTCH1byrh6WFvfBCN/wpherFz0a0bjGd7EKTst/cz0yLeNngug== + dependencies: + "@cto.af/textdecoder" "^0.0.0" + "nopt@2 || 3": version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -3289,7 +3506,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== -pidusage@2.0.21: +pidusage@2.0.21, pidusage@^2.0.21: version "2.0.21" resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-2.0.21.tgz#7068967b3d952baea73e57668c98b9eaa876894e" integrity sha512-cv3xAQos+pugVX+BfXpHsbyz/dLzX+lr44zNMsYiGxUw+kV5sgQCIcLd1z+0vq+KyC7dJ+/ts2PsfgWfSC3WXA== @@ -3338,7 +3555,7 @@ please-upgrade-node@^3.2.0: dependencies: semver-compare "^1.0.0" -pm2-axon-rpc@~0.7.0: +pm2-axon-rpc@~0.7.0, pm2-axon-rpc@~0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/pm2-axon-rpc/-/pm2-axon-rpc-0.7.1.tgz#2daec5383a63135b3f18babb70266dacdcbc429a" integrity sha512-FbLvW60w+vEyvMjP/xom2UPhUN/2bVpdtLfKJeYM3gwzYhoTEEChCOICfFzxkxuoEleOlnpjie+n1nue91bDQw== @@ -3370,12 +3587,23 @@ pm2-multimeter@^0.1.2: dependencies: charm "~0.1.1" -pm2@^4.5.6: - version "4.5.6" - resolved "https://registry.yarnpkg.com/pm2/-/pm2-4.5.6.tgz#2f477a158957860e440f1e71e88dc82627fcff99" - integrity sha512-4J5q704Xl6VmpmQhXFGMJL4kXyyQw3AZM1FE9vRxhS3LiDI/+WVBtOM6pqJ4g/RKW+AUjEkc23i/DCC4BVenDA== +pm2-sysmonit@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/pm2-sysmonit/-/pm2-sysmonit-1.2.8.tgz#eddea34a53fd8c8d7c3efb73b97a3c548686e24d" + integrity sha512-ACOhlONEXdCTVwKieBIQLSi2tQZ8eKinhcr9JpZSUAL8Qy0ajIgRtsLxG/lwPOW3JEKqPyw/UaHmTWhUzpP4kA== dependencies: - "@pm2/agent" "~1.0.8" + async "^3.2.0" + debug "^4.3.1" + pidusage "^2.0.21" + systeminformation "^5.7" + tx2 "~1.0.4" + +pm2@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/pm2/-/pm2-5.1.0.tgz#96afd4fcfeaf8739eef7f796115d3a014d5aa574" + integrity sha512-reJ35NOxM4+g7H0enW47HJsp32CszKkseCojAuUMUkffyXsGDKBMnDqhxAZMZKtHUUjl0cWFEqKehqB0ODH8Kw== + dependencies: + "@pm2/agent" "~2.0.0" "@pm2/io" "~5.0.0" "@pm2/js-api" "~0.6.7" "@pm2/pm2-version-check" latest @@ -3390,21 +3618,22 @@ pm2@^4.5.6: debug "^4.3.1" enquirer "2.3.6" eventemitter2 "5.0.1" + fast-printf "^1.3.0" fclone "1.0.11" mkdirp "1.0.4" needle "2.4.0" pidusage "2.0.21" pm2-axon "~4.0.1" - pm2-axon-rpc "~0.7.0" + pm2-axon-rpc "~0.7.1" pm2-deploy "~1.0.2" pm2-multimeter "^0.1.2" promptly "^2" - ps-list "6.3.0" semver "^7.2" source-map-support "0.5.19" - sprintf-js "1.1.2" - vizion "2.2.1" + vizion "~2.2.1" yamljs "0.3.0" + optionalDependencies: + pm2-sysmonit "^1.2.8" prelude-ls@~1.1.2: version "1.1.2" @@ -3440,7 +3669,7 @@ promptly@^2: dependencies: read "^1.0.4" -protobufjs@^6.8.6: +protobufjs@^6.10.0: version "6.11.2" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b" integrity sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw== @@ -3500,10 +3729,17 @@ proxy-from-env@^1.0.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -ps-list@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-6.3.0.tgz#a2b775c2db7d547a28fbaa3a05e4c281771259be" - integrity sha512-qau0czUSB0fzSlBOQt0bo+I2v6R+xiQdj78e1BR/Qjfl5OHWJ/urXi8+ilw1eHe+5hSeDI1wrwVTgDp2wst4oA== +psbt@1.1.10: + version "1.1.10" + resolved "https://registry.yarnpkg.com/psbt/-/psbt-1.1.10.tgz#559434bbe85aae9012fe7f99efb6b8e8efaecf50" + integrity sha512-LLyJcNVKRK8AUXKcpCrZA21+mlrjzlzTLQZp/Yu279hqqQrakAu9IusT7zEddhhkQrzm6UQ9cER3nhrIZqh0hw== + dependencies: + bip66 "1.1.5" + bitcoin-ops "1.4.1" + bitcoinjs-lib "5.2.0" + bn.js "5.2.0" + pushdata-bitcoin "1.0.1" + varuint-bitcoin "1.1.2" pseudomap@^1.0.2: version "1.0.2" @@ -3540,7 +3776,7 @@ pupa@^2.0.1: dependencies: escape-goat "^2.0.0" -pushdata-bitcoin@^1.0.1: +pushdata-bitcoin@1.0.1, pushdata-bitcoin@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz#15931d3cd967ade52206f523aa7331aef7d43af7" integrity sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc= @@ -3712,6 +3948,11 @@ request@^2.87.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + require-in-the-middle@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz#b768f800377b47526d026bbf5a7f727f16eb412f" @@ -4026,11 +4267,6 @@ split2@^3.1.1: dependencies: readable-stream "^3.0.0" -sprintf-js@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" - integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== - sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -4122,7 +4358,7 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.0.0, string-width@^4.1.0: +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: version "4.2.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== @@ -4202,6 +4438,11 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +systeminformation@^5.7: + version "5.8.0" + resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.8.0.tgz#43e6d0918d7d42c65e53e36059f0849354ab2873" + integrity sha512-l4drbK2PtNynGKblaShY9hDLW/gg1zxUq2+Yk4gTyd6a2JUvFyTGP8PhHV9iOh+MzS25PQa8W1t0kvcIvr9n7Q== + tar@^2.0.0: version "2.2.2" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" @@ -4341,6 +4582,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +tx2@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tx2/-/tx2-1.0.4.tgz#cb9432df22e0b8c54daf711b51b708f094449ddf" + integrity sha512-rU+y30nUY3PyIi+znvv74HzxlpULKwMPAyRK+YiCjvGkk3rY3fic3D6Z+avLpun3V5A6HFwPQ9JrBTMNEV/dxg== + dependencies: + json-stringify-safe "^5.0.1" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -4479,7 +4727,7 @@ validator@^10.11.0: resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== -varuint-bitcoin@^1.0.4: +varuint-bitcoin@1.1.2, varuint-bitcoin@^1.0.4: version "1.1.2" resolved "https://registry.yarnpkg.com/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz#e76c138249d06138b480d4c5b40ef53693e24e92" integrity sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw== @@ -4500,7 +4748,7 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vizion@2.2.1: +vizion@~2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/vizion/-/vizion-2.2.1.tgz#04201ea45ffd145d5b5210e385a8f35170387fb2" integrity sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww== @@ -4567,6 +4815,15 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -4587,16 +4844,11 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@^7.0.0, ws@^7.4.6: +ws@^7.0.0, ws@^7.4.6, ws@~7.4.0: version "7.4.6" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@~7.2.0: - version "7.2.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.5.tgz#abb1370d4626a5a9cd79d8de404aa18b3465d10d" - integrity sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA== - xdg-basedir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" @@ -4612,6 +4864,11 @@ xtend@^4.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" @@ -4635,6 +4892,24 @@ yamljs@0.3.0: argparse "^1.0.7" glob "^7.0.5" +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs@^16.1.1: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + zeromq@6.0.0-beta.6: version "6.0.0-beta.6" resolved "https://registry.yarnpkg.com/zeromq/-/zeromq-6.0.0-beta.6.tgz#2b8934cafce735ea9007fd3074ec8aca9bf11204" -- cgit v1.2.3 From 57749346e2f1762716e44d1dcb656d80f31f177c Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 4 Aug 2021 09:00:47 -0700 Subject: lnd v0.13.1-beta --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index c86ba2d1..00ddb05a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,7 @@ services: - ./config/liquid:/config restart: unless-stopped lnd: - image: lnd + image: lightninglabs/lnd:v0.13.1-beta container_name: lnd volumes: - ./config/lnd:/root/.lnd -- cgit v1.2.3 From db5888df67d7120c0ee5d77f36ddcedbeae5455e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 4 Aug 2021 14:15:38 -0400 Subject: move lnd require --- routes/lightning/send.js | 2 +- routes/payments.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/routes/lightning/send.js b/routes/lightning/send.js index f3c0da46..f6bd1b36 100644 --- a/routes/lightning/send.js +++ b/routes/lightning/send.js @@ -5,7 +5,7 @@ module.exports = ah(async (req, res) => { try { res.send(await send(amount, memo, payreq, user)); } catch (e) { - l.error("problem sending lightning payment", user.username, e.message, e.stack); + l.error("problem sending lightning payment", user.username, e.message); res.status(500).send(e.message); } }); diff --git a/routes/payments.js b/routes/payments.js index 70b711da..aa850839 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -2,7 +2,6 @@ const BitcoinCore = require("@asoltys/bitcoin-core"); const { Op } = require("sequelize"); const { join } = require("path"); const fs = require("fs"); -const lnd = require("../lib/lnd"); const read = require("../lib/read"); ah(async () => { @@ -96,6 +95,7 @@ ah(async () => { if (config.lna.clightning) { lna = require("clightning-client")(config.lna.dir); } else { + lnd = require("../lib/lnd"); lna = lnd.default; lnp = [ "addInvoice", -- cgit v1.2.3 From 5858323cf0bb920c9f967239b7a1ef7915cf0824 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 4 Aug 2021 17:08:25 -0700 Subject: don't wait for webhook to complete --- routes/assets.js | 11 ++++++++++- routes/bitcoin/receive.js | 4 ++-- routes/lightning/receive.js | 2 +- routes/liquid/receive.js | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/routes/assets.js b/routes/assets.js index fe667dd9..939eb76c 100644 --- a/routes/assets.js +++ b/routes/assets.js @@ -111,7 +111,15 @@ app.post( if (filename) contract.filename = filename; - l.info("attempting issuance", req.user.username, contract, "address", address, "pubkey", pubkey); + l.info( + "attempting issuance", + req.user.username, + contract, + "address", + address, + "pubkey", + pubkey + ); sha256.update(JSON.stringify(contract)); const hash = sha256.digest("hex"); @@ -128,6 +136,7 @@ app.post( contract_hash }; + params.asset_amount = asset_amount / (SATS / 10 ** precision); if (token_amount) { diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js index d782627d..67ccdb45 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -114,7 +114,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => { emit(user.username, "payment", payment); l.info("bitcoin detected", user.username, value); notify(user, `${value} SAT payment detected`); - await callWebhook(invoice, payment); + callWebhook(invoice, payment); } } catch (e) { console.log(e); @@ -189,7 +189,7 @@ setInterval(async () => { emit(user.username, "payment", p); l.info("bitcoin confirmed", user.username, p.amount, p.tip); notify(user, `${total} SAT payment confirmed`); - await callWebhook(p.invoice, p); + callWebhook(p.invoice, p); } else { l.warn("couldn't find bitcoin payment", hash); } diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js index 8d2aa750..39c5be15 100644 --- a/routes/lightning/receive.js +++ b/routes/lightning/receive.js @@ -67,7 +67,7 @@ const handlePayment = async msg => { payment = payment.get({ plain: true }); payment.account = account.get({ plain: true }); - await callWebhook(invoice, payment); + callWebhook(invoice, payment); emit(user.username, "payment", payment); emit(user.username, "account", payment.account); diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index 259db7c7..d3d4aec8 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -175,7 +175,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => { emit(user.username, "account", payment.account); l.info("liquid detected", address, user.username, asset, value); notify(user, `${value} SAT payment detected`); - await callWebhook(invoice, payment); + callWebhook(invoice, payment); }); } } catch (e) { -- cgit v1.2.3 From 97de1b7d9552d56a53c572b39fc7c7bc8cae242b Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 5 Aug 2021 11:35:16 -0700 Subject: capture invoice for ln and lbtc payments --- routes/lightning/receive.js | 3 ++- routes/liquid/receive.js | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js index 39c5be15..8d1e8917 100644 --- a/routes/lightning/receive.js +++ b/routes/lightning/receive.js @@ -50,7 +50,8 @@ const handlePayment = async msg => { received: true, confirmed: true, network: "lightning", - tip + tip, + invoice_id: invoice.id }, { transaction } ); diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index d3d4aec8..2c88075c 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -162,7 +162,8 @@ zmqRawTx.on("message", async (topic, message, sequence) => { tip, confirmed, address, - network: "liquid" + network: "liquid", + invoice_id: invoice.id }, { transaction } ); @@ -338,7 +339,7 @@ setInterval(async () => { ); notify(user, `${total} SAT payment confirmed`); - await callWebhook(p.invoice, p); + callWebhook(p.invoice, p); } else { l.warn("couldn't find liquid payment", hash); } -- cgit v1.2.3 From 2b7679cb963f42c10b97b48e794fd8594607e04f Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 5 Aug 2021 15:16:26 -0700 Subject: prettier --- routes/lightning/receive.js | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/routes/lightning/receive.js b/routes/lightning/receive.js index 8d1e8917..d974860e 100644 --- a/routes/lightning/receive.js +++ b/routes/lightning/receive.js @@ -1,19 +1,18 @@ -const handlePayment = async msg => { +const handlePayment = async (msg) => { if (!msg.settled) return; let account, total, user; const invoice = await db.Invoice.findOne({ where: { - text: msg.payment_request - } + text: msg.payment_request, + }, }); if (!invoice) return l.warn("received lightning with no invoice", msg.payment_request); try { - await db.transaction(async transaction => { - + await db.transaction(async (transaction) => { const { text: hash, currency, memo, rate, tip, user_id } = invoice; const amount = parseInt(msg.amt_paid_sat) - tip; if (amount > 10000000 || amount < 0) @@ -23,14 +22,14 @@ const handlePayment = async msg => { where: { user_id, asset: config.liquid.btcasset, - pubkey: null + pubkey: null, }, include: { model: db.User, - as: "user" + as: "user", }, lock: transaction.LOCK.UPDATE, - transaction + transaction, }); ({ user } = account); @@ -51,7 +50,7 @@ const handlePayment = async msg => { confirmed: true, network: "lightning", tip, - invoice_id: invoice.id + invoice_id: invoice.id, }, { transaction } ); @@ -98,7 +97,7 @@ const handlePayment = async msg => { address: c.address, amount: total - 100, user, - limit: total + limit: total, }); } catch (e) { l.error("problem sending liquid payment", e.message, e.stack); @@ -110,14 +109,14 @@ const handlePayment = async msg => { }; if (config.lna.clightning) { - const poll = async ln => { - const wait = async i => { + const poll = async (ln) => { + const wait = async (i) => { const { bolt11: payment_request, pay_index, status, msatoshi_received, - payment_preimage: r_preimage + payment_preimage: r_preimage, } = await ln.waitanyinvoice(i); let settled = status === "paid"; @@ -127,13 +126,13 @@ if (config.lna.clightning) { payment_request, settled, amt_paid_sat, - r_preimage + r_preimage, }); wait(pay_index); }; const { invoices } = await ln.listinvoices(); - wait(Math.max(...invoices.map(i => i.pay_index).filter(n => n))); + wait(Math.max(...invoices.map((i) => i.pay_index).filter((n) => n))); }; poll(lna); -- cgit v1.2.3 From 9b03ed9abead5d8d254fe537a8e003c6e468f63d Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 6 Aug 2021 08:51:34 -0700 Subject: zmq 6 syntax --- routes/bitcoin/receive.js | 234 +++++++++++++++++++++++----------------------- 1 file changed, 119 insertions(+), 115 deletions(-) diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js index 67ccdb45..572987cc 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -1,15 +1,15 @@ const reverse = require("buffer-reverse"); -const zmq = require("zeromq/v5-compat"); +const zmq = require("zeromq"); const { Op } = require("sequelize"); const { fromBase58 } = require("bip32"); const bitcoin = require("bitcoinjs-lib"); -const zmqRawBlock = zmq.socket("sub"); +const zmqRawBlock = new zmq.Subscriber(); zmqRawBlock.connect(config.bitcoin.zmqrawblock); -zmqRawBlock.subscribe("rawblock"); +zmqRawBlock.subscribe("rawtx"); -const zmqRawTx = zmq.socket("sub"); +const zmqRawTx = new zmq.Subscriber(); zmqRawTx.connect(config.bitcoin.zmqrawtx); zmqRawTx.subscribe("rawtx"); @@ -18,124 +18,128 @@ const network = config.bitcoin.network === "mainnet" ? "bitcoin" : config.bitcoin.network ]; -zmqRawTx.on("message", async (topic, message, sequence) => { - const hex = message.toString("hex"); - let tx = bitcoin.Transaction.fromHex(message); +let queue = {}; - let hash = reverse(tx.getHash()).toString("hex"); +(async () => { + for await (const [topic, message] of zmqRawTx) { + const hex = message.toString("hex"); + let tx = bitcoin.Transaction.fromHex(message); - if (payments.includes(hash)) return; + let hash = reverse(tx.getHash()).toString("hex"); - Promise.all( - tx.outs.map(async o => { - try { - const { value } = o; + if (payments.includes(hash)) return; - let address; + Promise.all( + tx.outs.map(async (o) => { try { - address = bitcoin.address.fromOutputScript(o.script, network); - } catch (e) { - return; - } + const { value } = o; - if ( - Object.keys(addresses).includes(address) && - !change.includes(address) - ) { - payments.push(hash); + let address; + try { + address = bitcoin.address.fromOutputScript(o.script, network); + } catch (e) { + return; + } - let user = await db.User.findOne({ - where: { - username: addresses[address] + if ( + Object.keys(addresses).includes(address) && + !change.includes(address) + ) { + payments.push(hash); + + let user = await db.User.findOne({ + where: { + username: addresses[address], + }, + }); + + const invoice = await db.Invoice.findOne({ + where: { + user_id: user.id, + network: "bitcoin", + }, + order: [["id", "DESC"]], + include: { + model: db.Account, + as: "account", + }, + }); + + if (!invoice) return; + + 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 : ""; + + let confirmed = false; + + let { account } = invoice; + + account.pending += value; + await account.save(); + + if (config.bitcoin.walletpass) + await bc.walletPassphrase(config.bitcoin.walletpass, 300); + + 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); + let inputTx = bitcoin.Transaction.fromHex(hex); + totalInputs += inputTx.outs[index].value; } - }); + let fee = totalInputs - totalOutputs; - const invoice = await db.Invoice.findOne({ - where: { + let payment = await db.Payment.create({ + account_id: account.id, user_id: user.id, - network: "bitcoin" - }, - order: [["id", "DESC"]], - include: { - model: db.Account, - as: "account" - } - }); - - if (!invoice) return; - - 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 : ""; - - let confirmed = false; - - let { account } = invoice; - - account.pending += value; - await account.save(); - - if (config.bitcoin.walletpass) - await bc.walletPassphrase(config.bitcoin.walletpass, 300); - - 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); - let inputTx = bitcoin.Transaction.fromHex(hex); - totalInputs += inputTx.outs[index].value; + hash, + fee, + memo, + amount: value - tip, + currency, + rate, + received: true, + tip, + confirmed, + address, + network: "bitcoin", + invoice_id: invoice.id, + }); + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); + + emit(user.username, "account", account); + + emit(user.username, "payment", payment); + l.info("bitcoin detected", user.username, value); + notify(user, `${value} SAT payment detected`); + callWebhook(invoice, payment); } - let fee = totalInputs - totalOutputs; - - let payment = await db.Payment.create({ - account_id: account.id, - user_id: user.id, - hash, - fee, - memo, - amount: value - tip, - currency, - rate, - received: true, - tip, - confirmed, - address, - network: "bitcoin", - invoice_id: invoice.id - }); - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); - - emit(user.username, "account", account); - - emit(user.username, "payment", payment); - l.info("bitcoin detected", user.username, value); - notify(user, `${value} SAT payment detected`); - callWebhook(invoice, payment); + } catch (e) { + console.log(e); } - } catch (e) { - console.log(e); - } - }) - ); -}); - -let queue = {}; + }) + ); + } -zmqRawBlock.on("message", async (topic, message, sequence) => { - const payments = await db.Payment.findAll({ - where: { confirmed: false } - }); + for await (const [topic, message] of zmqRawBlock) { + const payments = await db.Payment.findAll({ + where: { confirmed: false }, + }); - let block = bitcoin.Block.fromHex(message.toString("hex")); - block.transactions.map(tx => { - let hash = reverse(tx.getHash()).toString("hex"); - if (payments.find(p => p.hash === hash)) queue[hash] = 1; - }); -}); + let block = bitcoin.Block.fromHex(message.toString("hex")); + block.transactions.map((tx) => { + let hash = reverse(tx.getHash()).toString("hex"); + if (payments.find((p) => p.hash === hash)) queue[hash] = 1; + }); + } +})(); setInterval(async () => { try { @@ -144,25 +148,25 @@ setInterval(async () => { const hash = arr[i]; let account, address, user, total; - await db.transaction(async transaction => { + await db.transaction(async (transaction) => { let p = await db.Payment.findOne({ where: { hash, confirmed: 0, received: 1 }, include: [ { model: db.Account, - as: "account" + as: "account", }, { model: db.Invoice, - as: "invoice" + as: "invoice", }, { model: db.User, - as: "user" - } + as: "user", + }, ], lock: transaction.LOCK.UPDATE, - transaction + transaction, }); if (p && p.address) address = p.address; @@ -211,7 +215,7 @@ setInterval(async () => { address: c.address, amount: total - 100, user, - limit: total + limit: total, }); } } -- cgit v1.2.3 From 262e4bb11fedf1215bef58a7e472920e808a2d7e Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 6 Aug 2021 08:51:42 -0700 Subject: alpine docker base --- Dockerfile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 582778e2..e5f9f986 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,13 @@ -FROM node:slim +FROM node:alpine ARG NODE_ENV=production ENV NODE_ENV $NODE_ENV -RUN apt-get update -RUN apt-get install git make gcc g++ python libzmq3-dev -y +RUN apk add git COPY . /app WORKDIR /app RUN yarn install -ENV SHELL /bin/bash - CMD ["yarn", "start"] -- cgit v1.2.3 From 7f427d1c9e229bfd70e913db451a873ce561b8db Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 6 Aug 2021 14:58:01 -0700 Subject: fix zmq 6 syntax --- routes/bitcoin/receive.js | 6 +- routes/liquid/receive.js | 383 +++++++++++++++++++++++----------------------- routes/users.js | 2 +- 3 files changed, 199 insertions(+), 192 deletions(-) diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js index 572987cc..2e8114dd 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -7,7 +7,7 @@ const bitcoin = require("bitcoinjs-lib"); const zmqRawBlock = new zmq.Subscriber(); zmqRawBlock.connect(config.bitcoin.zmqrawblock); -zmqRawBlock.subscribe("rawtx"); +zmqRawBlock.subscribe("rawblock"); const zmqRawTx = new zmq.Subscriber(); zmqRawTx.connect(config.bitcoin.zmqrawtx); @@ -18,7 +18,7 @@ const network = config.bitcoin.network === "mainnet" ? "bitcoin" : config.bitcoin.network ]; -let queue = {}; +const queue = {}; (async () => { for await (const [topic, message] of zmqRawTx) { @@ -127,7 +127,9 @@ let queue = {}; }) ); } +})(); +(async () => { for await (const [topic, message] of zmqRawBlock) { const payments = await db.Payment.findAll({ where: { confirmed: false }, diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index 2c88075c..a30ff985 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -1,6 +1,6 @@ const axios = require("axios"); const reverse = require("buffer-reverse"); -const zmq = require("zeromq/v5-compat"); +const zmq = require("zeromq"); const { Op } = require("sequelize"); const { fromBase58 } = require("bip32"); const bitcoin = require("bitcoinjs-lib"); @@ -15,7 +15,7 @@ const getAccount = async (params, transaction) => { let account = await db.Account.findOne({ where: params, lock: transaction.LOCK.UPDATE, - transaction + transaction, }); if (account) { @@ -37,12 +37,12 @@ const getAccount = async (params, transaction) => { const existing = await db.Account.findOne({ where: { asset, - pubkey + pubkey, }, order: [["id", "ASC"]], limit: 1, lock: transaction.LOCK.UPDATE, - transaction + transaction, }); if (existing) { @@ -57,228 +57,233 @@ const getAccount = async (params, transaction) => { return db.Account.create(params, { transaction }); }; -const zmqRawBlock = zmq.socket("sub"); +const zmqRawBlock = new zmq.Subscriber(); zmqRawBlock.connect(config.liquid.zmqrawblock); zmqRawBlock.subscribe("rawblock"); -const zmqRawTx = zmq.socket("sub"); +const zmqRawTx = new zmq.Subscriber(); zmqRawTx.connect(config.liquid.zmqrawtx); zmqRawTx.subscribe("rawtx"); -zmqRawTx.on("message", async (topic, message, sequence) => { - const hex = message.toString("hex"); +const queue = {}; - let unblinded, tx, blinded; - try { - unblinded = await lq.unblindRawTransaction(hex); - tx = await lq.decodeRawTransaction(unblinded.hex); - blinded = await lq.decodeRawTransaction(hex); - } catch (e) { - return console.log(e); - } +(async () => { + for await (const [topic, message] of zmqRawTx) { + const hex = message.toString("hex"); - if (payments.includes(blinded.txid)) return; - - Promise.all( - tx.vout.map(async o => { - try { - if (!(o.scriptPubKey && o.scriptPubKey.addresses)) return; - - const { asset } = o; - const value = toSats(o.value); - const address = o.scriptPubKey.addresses[0]; - - if ( - Object.keys(addresses).includes(address) && - !change.includes(address) - ) { - await db.transaction(async transaction => { - let user = await getUser(addresses[address], transaction); - - let invoice = await db.Invoice.findOne({ - where: { - unconfidential: address, - user_id: user.id, - network: "liquid" - }, - order: [["id", "DESC"]] - }); + let unblinded, tx, blinded; + try { + unblinded = await lq.unblindRawTransaction(hex); + tx = await lq.decodeRawTransaction(unblinded.hex); + blinded = await lq.decodeRawTransaction(hex); + } catch (e) { + return console.log(e); + } - if (!invoice) return; + if (payments.includes(blinded.txid)) return; - let confirmed = 0; + Promise.all( + tx.vout.map(async (o) => { + try { + if (!(o.scriptPubKey && o.scriptPubKey.addresses)) return; - let account = await db.Account.findOne({ - where: { - id: invoice.account_id - }, - lock: transaction.LOCK.UPDATE, - transaction - }); + const { asset } = o; + const value = toSats(o.value); + const address = o.scriptPubKey.addresses[0]; - if ( - account.asset === asset && - (!account.pubkey || account.network === "liquid") - ) { - await account.increment({ pending: value }, { transaction }); - await account.reload({ transaction }); - } else { - account = await getAccount( - { - seed: account.seed, - path: account.path, + if ( + Object.keys(addresses).includes(address) && + !change.includes(address) + ) { + await db.transaction(async (transaction) => { + let user = await getUser(addresses[address], transaction); + + let invoice = await db.Invoice.findOne({ + where: { + unconfidential: address, user_id: user.id, - asset, - pubkey: account.pubkey, - pending: value, - index: 0 + network: "liquid", }, - transaction - ); - } + order: [["id", "DESC"]], + }); - if (config.liquid.walletpass) - await lq.walletPassphrase(config.liquid.walletpass, 300); - - await user.save({ transaction }); - - 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 : ""; - - let payment = await db.Payment.create( - { - account_id: account.id, - user_id: user.id, - hash: blinded.txid, - amount: value - tip, - currency, - memo, - rate, - received: true, - tip, - confirmed, - address, - network: "liquid", - invoice_id: invoice.id - }, - { transaction } - ); + if (!invoice) return; - payments.push(blinded.txid); - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); - - emit(user.username, "payment", payment); - emit(user.username, "account", payment.account); - l.info("liquid detected", address, user.username, asset, value); - notify(user, `${value} SAT payment detected`); - callWebhook(invoice, payment); - }); - } - } catch (e) { - l.error("Problem processing transaction", e.message, e.stack); - } - }) - ); -}); + let confirmed = 0; -let queue = {}; - -zmqRawBlock.on("message", async (topic, message, sequence) => { - try { - const payments = await db.Payment.findAll({ - where: { confirmed: 0 } - }); - - const block = Block.fromHex(message.toString("hex"), true); - - let hash, json; + let account = await db.Account.findOne({ + where: { + id: invoice.account_id, + }, + lock: transaction.LOCK.UPDATE, + transaction, + }); + + if ( + account.asset === asset && + (!account.pubkey || account.network === "liquid") + ) { + await account.increment({ pending: value }, { transaction }); + await account.reload({ transaction }); + } else { + account = await getAccount( + { + seed: account.seed, + path: account.path, + user_id: user.id, + asset, + pubkey: account.pubkey, + pending: value, + index: 0, + }, + transaction + ); + } + + if (config.liquid.walletpass) + await lq.walletPassphrase(config.liquid.walletpass, 300); + + await user.save({ transaction }); + + 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 : ""; + + let payment = await db.Payment.create( + { + account_id: account.id, + user_id: user.id, + hash: blinded.txid, + amount: value - tip, + currency, + memo, + rate, + received: true, + tip, + confirmed, + address, + network: "liquid", + invoice_id: invoice.id, + }, + { transaction } + ); - hash = await lq.getBlockHash(block.height); - json = await lq.getBlock(hash, 2); + payments.push(blinded.txid); + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); - json.tx.map(async tx => { - if (issuances[tx.txid]) { - await db.transaction(async transaction => { - const { - user_id, - asset, - asset_amount, - asset_payment_id, - token, - token_amount, - token_payment_id - } = issuances[tx.txid]; + emit(user.username, "payment", payment); + emit(user.username, "account", payment.account); + l.info("liquid detected", address, user.username, asset, value); + notify(user, `${value} SAT payment detected`); + callWebhook(invoice, payment); + }); + } + } catch (e) { + l.error("Problem processing transaction", e.message, e.stack); + } + }) + ); + } +})(); + +(async () => { + for await (const [topic, message] of zmqRawBlock) { + console.log(message); + try { + const payments = await db.Payment.findAll({ + where: { confirmed: 0 }, + }); - const user = await getUserById(user_id); + const block = Block.fromHex(message.toString("hex"), true); - let account = await db.Account.findOne({ - where: { user_id, asset }, - lock: transaction.LOCK.UPDATE, - transaction - }); - account.balance = asset_amount * SATS; - account.pending = 0; - await account.save({ transaction }); + let hash, json; - let payment = await db.Payment.findOne({ - where: { id: asset_payment_id }, - include: { - model: db.Account, - as: "account" - }, - lock: transaction.LOCK.UPDATE, - transaction - }); + hash = await lq.getBlockHash(block.height); + json = await lq.getBlock(hash, 2); - payment.confirmed = true; - await payment.save({ transaction }); - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); + json.tx.map(async (tx) => { + if (issuances[tx.txid]) { + await db.transaction(async (transaction) => { + const { + user_id, + asset, + asset_amount, + asset_payment_id, + token, + token_amount, + token_payment_id, + } = issuances[tx.txid]; - emit(user.username, "account", account); - emit(user.username, "payment", payment); + const user = await getUserById(user_id); - if (token) { - account = await db.Account.findOne({ - where: { user_id, asset: token }, + let account = await db.Account.findOne({ + where: { user_id, asset }, lock: transaction.LOCK.UPDATE, - transaction + transaction, }); - account.balance = token_amount * SATS; + account.balance = asset_amount * SATS; account.pending = 0; await account.save({ transaction }); - payment = await db.Payment.findOne({ - where: { id: token_payment_id }, + let payment = await db.Payment.findOne({ + where: { id: asset_payment_id }, include: { model: db.Account, - as: "account" + as: "account", }, lock: transaction.LOCK.UPDATE, - transaction + transaction, }); payment.confirmed = true; await payment.save({ transaction }); - payment = payment.get({ plain: true }); payment.account = account.get({ plain: true }); emit(user.username, "account", account); emit(user.username, "payment", payment); - } - }); - } else if (payments.find(p => p.hash === tx.txid)) queue[tx.txid] = 1; - }); - } catch (e) { - return console.log(e); + + if (token) { + account = await db.Account.findOne({ + where: { user_id, asset: token }, + lock: transaction.LOCK.UPDATE, + transaction, + }); + account.balance = token_amount * SATS; + account.pending = 0; + await account.save({ transaction }); + + payment = await db.Payment.findOne({ + where: { id: token_payment_id }, + include: { + model: db.Account, + as: "account", + }, + lock: transaction.LOCK.UPDATE, + transaction, + }); + + payment.confirmed = true; + await payment.save({ transaction }); + + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); + + emit(user.username, "account", account); + emit(user.username, "payment", payment); + } + }); + } else if (payments.find((p) => p.hash === tx.txid)) queue[tx.txid] = 1; + }); + } catch (e) { + return console.log(e); + } } -}); +})(); setInterval(async () => { try { @@ -288,25 +293,25 @@ setInterval(async () => { const hash = arr[i]; let account, address, user, total, p; - await db.transaction(async transaction => { + await db.transaction(async (transaction) => { p = await db.Payment.findOne({ where: { hash, confirmed: 0, received: 1 }, include: [ { model: db.Account, - as: "account" + as: "account", }, { model: db.Invoice, - as: "invoice" + as: "invoice", }, { model: db.User, - as: "user" - } + as: "user", + }, ], lock: transaction.LOCK.UPDATE, - transaction + transaction, }); ({ account, address, user } = p); @@ -362,7 +367,7 @@ setInterval(async () => { address: c.address, amount: total - 100, user, - limit: total + limit: total, }); } } diff --git a/routes/users.js b/routes/users.js index 23f016c7..24138fb6 100644 --- a/routes/users.js +++ b/routes/users.js @@ -5,7 +5,7 @@ const authenticator = require("otplib").authenticator; const getAccount = require("../lib/account"); const Sequelize = require("sequelize"); const bitcoin = require("bitcoinjs-lib"); -const liquid = require("@asoltys/liquidjs-lib"); +// const liquid = require("@asoltys/liquidjs-lib"); const { fromBase58, fromPrivateKey } = require("bip32"); const { Mutex } = require("async-mutex"); const bip32 = require("bip32"); -- cgit v1.2.3 From 3eebf4fa82fdbd2026eeaa1d6615366f24d498f3 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 6 Aug 2021 20:18:33 -0700 Subject: remove comments --- lib/persist.js | 2 -- routes/users.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/persist.js b/lib/persist.js index 54e7e209..a2febf68 100644 --- a/lib/persist.js +++ b/lib/persist.js @@ -7,8 +7,6 @@ module.exports = (path, initial = {}) => { } catch(e) {} } - // console.log("initial", path, initial); - return new Proxy(initial, { set(obj, prop, value) { fs.writeFileSync( diff --git a/routes/users.js b/routes/users.js index 24138fb6..23f016c7 100644 --- a/routes/users.js +++ b/routes/users.js @@ -5,7 +5,7 @@ const authenticator = require("otplib").authenticator; const getAccount = require("../lib/account"); const Sequelize = require("sequelize"); const bitcoin = require("bitcoinjs-lib"); -// const liquid = require("@asoltys/liquidjs-lib"); +const liquid = require("@asoltys/liquidjs-lib"); const { fromBase58, fromPrivateKey } = require("bip32"); const { Mutex } = require("async-mutex"); const bip32 = require("bip32"); -- cgit v1.2.3 From bcf89f097f9a62a2aeac70da17ab527b243e811a Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Mon, 9 Aug 2021 19:11:31 -0700 Subject: back to v5 zmq --- routes/assets.js | 2 +- routes/bitcoin/receive.js | 200 +++++++++++++------------- routes/liquid/receive.js | 353 +++++++++++++++++++++++----------------------- 3 files changed, 272 insertions(+), 283 deletions(-) diff --git a/routes/assets.js b/routes/assets.js index 939eb76c..0a71bbb8 100644 --- a/routes/assets.js +++ b/routes/assets.js @@ -157,7 +157,7 @@ app.post( const brt = await lq.blindRawTransaction(hex, true, [], false); const srt = await lq.signRawTransactionWithWallet(brt); const allowed = (await lq.testMempoolAccept([srt.hex]))[0].allowed; - if (!allowed) throw new Error("issuance rejected by mempool"); + if (!allowed) throw new Error("issuance rejected by mempool", srt.hex); const txid = await lq.sendRawTransaction(srt.hex); await db.transaction(async transaction => { diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js index 2e8114dd..603db47b 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -1,15 +1,15 @@ const reverse = require("buffer-reverse"); -const zmq = require("zeromq"); +const zmq = require("zeromq/v5-compat"); const { Op } = require("sequelize"); const { fromBase58 } = require("bip32"); const bitcoin = require("bitcoinjs-lib"); -const zmqRawBlock = new zmq.Subscriber(); +const zmqRawBlock = zmq.socket("sub"); zmqRawBlock.connect(config.bitcoin.zmqrawblock); zmqRawBlock.subscribe("rawblock"); -const zmqRawTx = new zmq.Subscriber(); +const zmqRawTx = zmq.socket("sub"); zmqRawTx.connect(config.bitcoin.zmqrawtx); zmqRawTx.subscribe("rawtx"); @@ -20,117 +20,112 @@ const network = const queue = {}; -(async () => { - for await (const [topic, message] of zmqRawTx) { - const hex = message.toString("hex"); - let tx = bitcoin.Transaction.fromHex(message); +zmqRawTx.on("message", async (topic, message, sequence) => { + const hex = message.toString("hex"); + let tx = bitcoin.Transaction.fromHex(message); - let hash = reverse(tx.getHash()).toString("hex"); + let hash = reverse(tx.getHash()).toString("hex"); - if (payments.includes(hash)) return; + if (payments.includes(hash)) return; - Promise.all( - tx.outs.map(async (o) => { + Promise.all( + tx.outs.map(async (o) => { + try { + const { value } = o; + + let address; try { - const { value } = o; + address = bitcoin.address.fromOutputScript(o.script, network); + } catch (e) { + return; + } - let address; - try { - address = bitcoin.address.fromOutputScript(o.script, network); - } catch (e) { - return; - } + if ( + Object.keys(addresses).includes(address) && + !change.includes(address) + ) { + payments.push(hash); + + let user = await db.User.findOne({ + where: { + username: addresses[address], + }, + }); - if ( - Object.keys(addresses).includes(address) && - !change.includes(address) - ) { - payments.push(hash); - - let user = await db.User.findOne({ - where: { - username: addresses[address], - }, - }); - - const invoice = await db.Invoice.findOne({ - where: { - user_id: user.id, - network: "bitcoin", - }, - order: [["id", "DESC"]], - include: { - model: db.Account, - as: "account", - }, - }); - - if (!invoice) return; - - 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 : ""; - - let confirmed = false; - - let { account } = invoice; - - account.pending += value; - await account.save(); - - if (config.bitcoin.walletpass) - await bc.walletPassphrase(config.bitcoin.walletpass, 300); - - 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); - 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, + const invoice = await db.Invoice.findOne({ + where: { user_id: user.id, - hash, - fee, - memo, - amount: value - tip, - currency, - rate, - received: true, - tip, - confirmed, - address, network: "bitcoin", - invoice_id: invoice.id, - }); - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); + }, + order: [["id", "DESC"]], + include: { + model: db.Account, + as: "account", + }, + }); + + if (!invoice) return; + + 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 : ""; - emit(user.username, "account", account); + let confirmed = false; - emit(user.username, "payment", payment); - l.info("bitcoin detected", user.username, value); - notify(user, `${value} SAT payment detected`); - callWebhook(invoice, payment); + let { account } = invoice; + + account.pending += value; + await account.save(); + + if (config.bitcoin.walletpass) + await bc.walletPassphrase(config.bitcoin.walletpass, 300); + + 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); + let inputTx = bitcoin.Transaction.fromHex(hex); + totalInputs += inputTx.outs[index].value; } - } catch (e) { - console.log(e); + let fee = totalInputs - totalOutputs; + + let payment = await db.Payment.create({ + account_id: account.id, + user_id: user.id, + hash, + fee, + memo, + amount: value - tip, + currency, + rate, + received: true, + tip, + confirmed, + address, + network: "bitcoin", + invoice_id: invoice.id, + }); + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); + + emit(user.username, "account", account); + + emit(user.username, "payment", payment); + l.info("bitcoin detected", user.username, value); + notify(user, `${value} SAT payment detected`); + callWebhook(invoice, payment); } - }) - ); - } -})(); + } catch (e) { + console.log(e); + } + }) + ); +}); -(async () => { - for await (const [topic, message] of zmqRawBlock) { +zmqRawBlock.on("message", async (topic, message, sequence) => { const payments = await db.Payment.findAll({ where: { confirmed: false }, }); @@ -140,8 +135,7 @@ const queue = {}; let hash = reverse(tx.getHash()).toString("hex"); if (payments.find((p) => p.hash === hash)) queue[hash] = 1; }); - } -})(); + }); setInterval(async () => { try { diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index a30ff985..2396755f 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -1,6 +1,6 @@ const axios = require("axios"); const reverse = require("buffer-reverse"); -const zmq = require("zeromq"); +const zmq = require("zeromq/v5-compat"); const { Op } = require("sequelize"); const { fromBase58 } = require("bip32"); const bitcoin = require("bitcoinjs-lib"); @@ -57,180 +57,204 @@ const getAccount = async (params, transaction) => { return db.Account.create(params, { transaction }); }; -const zmqRawBlock = new zmq.Subscriber(); +const zmqRawBlock = zmq.socket("sub"); zmqRawBlock.connect(config.liquid.zmqrawblock); zmqRawBlock.subscribe("rawblock"); -const zmqRawTx = new zmq.Subscriber(); +const zmqRawTx = zmq.socket("sub"); zmqRawTx.connect(config.liquid.zmqrawtx); zmqRawTx.subscribe("rawtx"); const queue = {}; -(async () => { - for await (const [topic, message] of zmqRawTx) { - const hex = message.toString("hex"); - - let unblinded, tx, blinded; - try { - unblinded = await lq.unblindRawTransaction(hex); - tx = await lq.decodeRawTransaction(unblinded.hex); - blinded = await lq.decodeRawTransaction(hex); - } catch (e) { - return console.log(e); - } +zmqRawTx.on("message", async (topic, message, sequence) => { + const hex = message.toString("hex"); - if (payments.includes(blinded.txid)) return; + let unblinded, tx, blinded; + try { + unblinded = await lq.unblindRawTransaction(hex); + tx = await lq.decodeRawTransaction(unblinded.hex); + blinded = await lq.decodeRawTransaction(hex); + } catch (e) { + return console.log(e); + } - Promise.all( - tx.vout.map(async (o) => { - try { - if (!(o.scriptPubKey && o.scriptPubKey.addresses)) return; + if (payments.includes(blinded.txid)) return; - const { asset } = o; - const value = toSats(o.value); - const address = o.scriptPubKey.addresses[0]; + Promise.all( + tx.vout.map(async (o) => { + try { + if (!(o.scriptPubKey && o.scriptPubKey.addresses)) return; - if ( - Object.keys(addresses).includes(address) && - !change.includes(address) - ) { - await db.transaction(async (transaction) => { - let user = await getUser(addresses[address], transaction); + const { asset } = o; + const value = toSats(o.value); + const address = o.scriptPubKey.addresses[0]; - let invoice = await db.Invoice.findOne({ - where: { - unconfidential: address, - user_id: user.id, - network: "liquid", - }, - order: [["id", "DESC"]], - }); + if ( + Object.keys(addresses).includes(address) && + !change.includes(address) + ) { + await db.transaction(async (transaction) => { + let user = await getUser(addresses[address], transaction); - if (!invoice) return; + let invoice = await db.Invoice.findOne({ + where: { + unconfidential: address, + user_id: user.id, + network: "liquid", + }, + order: [["id", "DESC"]], + }); - let confirmed = 0; + if (!invoice) return; - let account = await db.Account.findOne({ - where: { - id: invoice.account_id, - }, - lock: transaction.LOCK.UPDATE, - transaction, - }); - - if ( - account.asset === asset && - (!account.pubkey || account.network === "liquid") - ) { - await account.increment({ pending: value }, { transaction }); - await account.reload({ transaction }); - } else { - account = await getAccount( - { - seed: account.seed, - path: account.path, - user_id: user.id, - asset, - pubkey: account.pubkey, - pending: value, - index: 0, - }, - transaction - ); - } - - if (config.liquid.walletpass) - await lq.walletPassphrase(config.liquid.walletpass, 300); - - await user.save({ transaction }); - - 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 : ""; - - let payment = await db.Payment.create( + let confirmed = 0; + + let account = await db.Account.findOne({ + where: { + id: invoice.account_id, + }, + lock: transaction.LOCK.UPDATE, + transaction, + }); + + if ( + account.asset === asset && + (!account.pubkey || account.network === "liquid") + ) { + await account.increment({ pending: value }, { transaction }); + await account.reload({ transaction }); + } else { + account = await getAccount( { - account_id: account.id, + seed: account.seed, + path: account.path, user_id: user.id, - hash: blinded.txid, - amount: value - tip, - currency, - memo, - rate, - received: true, - tip, - confirmed, - address, - network: "liquid", - invoice_id: invoice.id, + asset, + pubkey: account.pubkey, + pending: value, + index: 0, }, - { transaction } + transaction ); + } - payments.push(blinded.txid); - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); + if (config.liquid.walletpass) + await lq.walletPassphrase(config.liquid.walletpass, 300); + + await user.save({ transaction }); + + 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 : ""; + + let payment = await db.Payment.create( + { + account_id: account.id, + user_id: user.id, + hash: blinded.txid, + amount: value - tip, + currency, + memo, + rate, + received: true, + tip, + confirmed, + address, + network: "liquid", + invoice_id: invoice.id, + }, + { transaction } + ); - emit(user.username, "payment", payment); - emit(user.username, "account", payment.account); - l.info("liquid detected", address, user.username, asset, value); - notify(user, `${value} SAT payment detected`); - callWebhook(invoice, payment); - }); - } - } catch (e) { - l.error("Problem processing transaction", e.message, e.stack); + payments.push(blinded.txid); + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); + + emit(user.username, "payment", payment); + emit(user.username, "account", payment.account); + l.info("liquid detected", address, user.username, asset, value); + notify(user, `${value} SAT payment detected`); + callWebhook(invoice, payment); + }); } - }) - ); - } -})(); - -(async () => { - for await (const [topic, message] of zmqRawBlock) { - console.log(message); - try { - const payments = await db.Payment.findAll({ - where: { confirmed: 0 }, - }); + } catch (e) { + l.error("Problem processing transaction", e.message, e.stack); + } + }) + ); +}); - const block = Block.fromHex(message.toString("hex"), true); +zmqRawBlock.on("message", async (topic, message, sequence) => { + try { + const payments = await db.Payment.findAll({ + where: { confirmed: 0 }, + }); - let hash, json; + const block = Block.fromHex(message.toString("hex"), true); - hash = await lq.getBlockHash(block.height); - json = await lq.getBlock(hash, 2); + let hash, json; - json.tx.map(async (tx) => { - if (issuances[tx.txid]) { - await db.transaction(async (transaction) => { - const { - user_id, - asset, - asset_amount, - asset_payment_id, - token, - token_amount, - token_payment_id, - } = issuances[tx.txid]; - - const user = await getUserById(user_id); + hash = await lq.getBlockHash(block.height); + json = await lq.getBlock(hash, 2); - let account = await db.Account.findOne({ - where: { user_id, asset }, + json.tx.map(async (tx) => { + if (issuances[tx.txid]) { + await db.transaction(async (transaction) => { + const { + user_id, + asset, + asset_amount, + asset_payment_id, + token, + token_amount, + token_payment_id, + } = issuances[tx.txid]; + + const user = await getUserById(user_id); + + let account = await db.Account.findOne({ + where: { user_id, asset }, + lock: transaction.LOCK.UPDATE, + transaction, + }); + account.balance = asset_amount * SATS; + account.pending = 0; + await account.save({ transaction }); + + let payment = await db.Payment.findOne({ + where: { id: asset_payment_id }, + include: { + model: db.Account, + as: "account", + }, + lock: transaction.LOCK.UPDATE, + transaction, + }); + + payment.confirmed = true; + await payment.save({ transaction }); + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); + + emit(user.username, "account", account); + emit(user.username, "payment", payment); + + if (token) { + account = await db.Account.findOne({ + where: { user_id, asset: token }, lock: transaction.LOCK.UPDATE, transaction, }); - account.balance = asset_amount * SATS; + account.balance = token_amount * SATS; account.pending = 0; await account.save({ transaction }); - let payment = await db.Payment.findOne({ - where: { id: asset_payment_id }, + payment = await db.Payment.findOne({ + where: { id: token_payment_id }, include: { model: db.Account, as: "account", @@ -241,49 +265,20 @@ const queue = {}; payment.confirmed = true; await payment.save({ transaction }); + payment = payment.get({ plain: true }); payment.account = account.get({ plain: true }); emit(user.username, "account", account); emit(user.username, "payment", payment); - - if (token) { - account = await db.Account.findOne({ - where: { user_id, asset: token }, - lock: transaction.LOCK.UPDATE, - transaction, - }); - account.balance = token_amount * SATS; - account.pending = 0; - await account.save({ transaction }); - - payment = await db.Payment.findOne({ - where: { id: token_payment_id }, - include: { - model: db.Account, - as: "account", - }, - lock: transaction.LOCK.UPDATE, - transaction, - }); - - payment.confirmed = true; - await payment.save({ transaction }); - - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); - - emit(user.username, "account", account); - emit(user.username, "payment", payment); - } - }); - } else if (payments.find((p) => p.hash === tx.txid)) queue[tx.txid] = 1; - }); - } catch (e) { - return console.log(e); - } + } + }); + } else if (payments.find((p) => p.hash === tx.txid)) queue[tx.txid] = 1; + }); + } catch (e) { + return console.log(e); } -})(); +}); setInterval(async () => { try { @@ -374,4 +369,4 @@ setInterval(async () => { } catch (e) { l.error("problem processing queued liquid transaction", e.message, e.stack); } -}, 1000); +}); -- cgit v1.2.3 From 8d6f65079868ae6134f593752e3380180591623d Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Mon, 9 Aug 2021 20:44:47 -0700 Subject: don't delete invoice on lnurl creation --- routes/lnurl.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/routes/lnurl.js b/routes/lnurl.js index adf4df7c..67f581d1 100644 --- a/routes/lnurl.js +++ b/routes/lnurl.js @@ -129,16 +129,6 @@ app.get( maxSendable = maxSendable || 1000000000; if (parseInt(amount)) minSendable = maxSendable = amount * 1000; - let invoices = await db.Invoice.findAll({ - where: { - amount - }, - order: [["id", "DESC"]], - limit: 1 - }); - - if (invoices.length) await invoices[0].destroy(); - try { const result = await lnurlServer.generateNewUrl("payRequest", { minSendable, -- cgit v1.2.3