From 33229e38a910e26083175a3e272278745378114c Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 17 Jan 2023 16:05:00 -0800 Subject: redlock --- routes/info.js | 90 +++++++++++----------------------------------------------- 1 file changed, 16 insertions(+), 74 deletions(-) (limited to 'routes/info.js') diff --git a/routes/info.js b/routes/info.js index eb42ca35..00a4915e 100644 --- a/routes/info.js +++ b/routes/info.js @@ -1,90 +1,32 @@ -import app from "$app"; -import db from "$db"; -import config from "$config"; -import store from "$lib/store"; - -import bc from "$lib/bitcoin"; -import lq from "$lib/liquid"; +import db from "$lib/db"; import ln from "$lib/ln"; -import sequelize from "@sequelize/core"; -import { SATS } from "$lib/utils"; - -const { Op } = sequelize; - -/** - * @api {get} /info Request server information - * @apiName GetInfo - * @apiGroup Info - * - * @apiSuccess {Object} fx Exchange rates relative to USD - fx.CUR is the value of one CUR in USD. - * @apiSuccess {String[]} networks Array of supported networks; possible values are "bitcoin", "liquid" and "lightning". - * @apiSuccess {String} clientVersion the current git commit of the ui - */ -app.get("/info", async (req, res, next) => { - const { clientVersion } = config; - - const info = { - fx: store.fx, - nodes: store.networks, - clientVersion - }; - - res.send(info); -}); +export default { + async balances(req, res) { + let lnchannel; + let lnwallet; -app.get("/balances", async (req, res, next) => { - try { - const accounts = await db.Account.findAll({ - where: { - pubkey: null - }, - attributes: [ - "asset", - [sequelize.fn("sum", sequelize.col("balance")), "total"] - ], - group: ["asset"] + const stream = db.scanStream({ + match: "balance:*", + count: 100 }); - let lnchannel; - let lnwallet; + let b = 0; + for await (let keys of stream) { + for (let k of keys) b += parseInt(await db.get(k)); + } + console.log(b) const funds = await ln.listfunds(); lnchannel = parseInt(funds.channels.reduce((a, b) => a + b.channel_sat, 0)); lnwallet = parseInt(funds.outputs.reduce((a, b) => a + b.value, 0)); - let bitcoin, bitcoind; - if (config.bitcoin) { - bitcoin = parseInt((await bc.getBalance()) * SATS); - bitcoind = await bc.getNetworkInfo(); - } - - let assets, liquid, elementsd; - if (config.liquid) { - assets = await lq.getBalance(); - liquid = parseInt(assets.bitcoin * SATS); - elementsd = await lq.getNetworkInfo(); - } - const info = { - bitcoind, - elementsd, - accounts, - assets, - bitcoin, - liquid, lnchannel, - lnwallet + lnwallet, + total: lnchannel + lnwallet }; - info.total = - parseInt(bitcoin) + - parseInt(liquid) + - parseInt(lnchannel) + - parseInt(lnwallet); - res.send(info); - } catch (e) { - console.log("problem getting balances", e); } -}); +}; -- cgit v1.2.3 From 2edcafb31e954628689e769c6926e3e48ddf84eb Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 22 Jan 2023 21:04:41 -0800 Subject: on chain send --- index.js | 3 ++ lib/payments.js | 9 ++--- lib/utils.js | 1 + routes/info.js | 2 +- routes/invoices.js | 1 - routes/payments.js | 112 ++++++++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 111 insertions(+), 17 deletions(-) (limited to 'routes/info.js') diff --git a/index.js b/index.js index 31739f8a..99058833 100644 --- a/index.js +++ b/index.js @@ -50,7 +50,10 @@ app.get("/payments/:hash", auth, payments.get); app.post("/parse", payments.parse); app.get("/pot/:name", payments.pot); app.post("/take", auth, payments.take); + app.post("/bitcoin", payments.bitcoin); +app.post("/bitcoin/fee", auth, payments.fee); +app.post("/bitcoin/send", auth, payments.send); app.get("/me", auth, users.me); app.get("/users/:key", users.get); diff --git a/lib/payments.js b/lib/payments.js index af08cb84..d25df227 100644 --- a/lib/payments.js +++ b/lib/payments.js @@ -18,16 +18,15 @@ export const types = { export let debit = async ( hash, amount, + fee = 0, memo, user, type = types.internal, id = v4() ) => { - console.log("HASH", hash) let ref; let invoice = await g(`invoice:${hash}`); if (invoice) ref = invoice.uid; - console.log("REF", ref) let { id: uid, currency, username } = user; @@ -41,13 +40,13 @@ export let debit = async ( return balance - amount; }); - let fee = 0; - let p = { id, amount: -amount, + fee, memo, uid, + confirmed: true, rate: store.rates[currency], currency, type, @@ -102,7 +101,7 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { balance = "pending"; } else { p.id = hash; - } + } await db .multi() diff --git a/lib/utils.js b/lib/utils.js index b65f179a..e58f7d1f 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -24,6 +24,7 @@ export const fail = msg => { export const SATS = 100000000; export const sats = n => Math.round(n * SATS); +export const btc = n => parseFloat((n / SATS).toFixed(8)); export const uniq = (a, k) => [...new Map(a.map(x => [k(x), x])).values()]; export const pick = (O, K) => diff --git a/routes/info.js b/routes/info.js index 00a4915e..017e473a 100644 --- a/routes/info.js +++ b/routes/info.js @@ -15,7 +15,7 @@ export default { for await (let keys of stream) { for (let k of keys) b += parseInt(await db.get(k)); } - console.log(b) + console.log(b); const funds = await ln.listfunds(); lnchannel = parseInt(funds.channels.reduce((a, b) => a + b.channel_sat, 0)); diff --git a/routes/invoices.js b/routes/invoices.js index 8fbb25c1..5da481e1 100644 --- a/routes/invoices.js +++ b/routes/invoices.js @@ -34,7 +34,6 @@ export default { if (amount < 0) fail("invalid amount"); let hash, text; - console.log("TYPE", type) if (type === types.lightning) { let amt = amount ? `${amount + tip}sat` : "any"; let r = await ln.invoice(amt, new Date(), "", 3600); diff --git a/routes/payments.js b/routes/payments.js index b92a6f81..80d8818f 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -4,7 +4,7 @@ import { emit } from "$lib/sockets"; import { v4 } from "uuid"; import { db, g, s, t } from "$lib/db"; import { l, err } from "$lib/logging"; -import { fail, sats } from "$lib/utils"; +import { fail, btc, sats } from "$lib/utils"; import { requirePin } from "$lib/auth"; import { debit, credit, confirm, types } from "$lib/payments"; @@ -15,15 +15,41 @@ const { HOSTNAME: hostname } = process.env; export default { async create({ body, user }, res) { - let { amount, hash, name, memo, tip } = body; - await requirePin({ body, user }); + let { amount, hash, maxfee, name, memo, payreq, tip } = body; + + amount = parseInt(amount); + maxfee = parseInt(maxfee); + tip = parseInt(tip); - let p = await debit(hash, amount, memo, user); + await requirePin({ body, user }); - if (hash) { + let p; + + if (payreq) { + p = await debit( + hash, + amount + maxfee, + maxfee, + memo, + user, + types.lightning + ); + + let r = await ln.pay(payreq); + + p.amount = -amount; + p.hash = r.payment_hash; + p.fee = r.msatoshi_sent - r.msatoshi; + p.preimage = r.payment_preimage; + + await s(`payment:${p.id}`, p); + await db.incrBy(`balance:${p.uid}`, maxfee - p.fee); + } else if (hash) { + p = await debit(hash, amount, 0, memo, user); await credit(hash, amount, memo, user.id); } else { let pot = name || v4(); + p = await debit(hash, amount, 0, memo, user); await db.incrBy(`pot:${pot}`, amount); await db.lPush(`pot:${pot}:payments`, p.id); l("funded pot", pot); @@ -65,13 +91,11 @@ export default { let twoWeeksAgo = new Date(new Date().setDate(new Date().getDate() - 14)); let decoded = await ln.decodepay(payreq); - let { msatoshi, payee, routes } = decoded; + let { msatoshi, payee } = decoded; let node = nodes.find(n => n.nodeid === payee); let alias = node ? node.alias : payee.substr(0, 12); - let r = await ln.getroute(payee, msatoshi, 5); - console.log(routes, r); - res.send({ alias, amount: Math.round(msatoshi / 1000), routes }); + res.send({ alias, amount: Math.round(msatoshi / 1000) }); }, async pot({ params: { name } }, res) { @@ -90,7 +114,6 @@ export default { async take({ body: { name, amount }, user }, res) { amount = parseInt(amount); await t(`pot:${name}`, async balance => { - await new Promise(r => setTimeout(r, 100)); if (balance < amount) fail("Insufficient funds"); return balance - amount; }); @@ -125,5 +148,74 @@ export default { } } res.send({}); + }, + + async fee(req, res) { + let { amount, address, feeRate, subtract } = req.body; + let subtractFeeFromOutputs = subtract ? [0] : []; + let replaceable = true; + let outs = [{ [address]: btc(amount) }]; + let count = await bc.getBlockCount(); + + let raw = await bc.createRawTransaction([], outs, 0, replaceable); + let tx = await bc.fundRawTransaction(raw, { + feeRate, + subtractFeeFromOutputs, + replaceable + }); + + if (config.bitcoin.walletpass) + await bc.walletPassphrase(config.bitcoin.walletpass, 300); + + let { hex } = await bc.signRawTransactionWithWallet(tx.hex); + let { vsize } = await bc.decodeRawTransaction(hex); + feeRate = Math.round((sats(tx.fee) * 1000) / vsize); + + res.send({ feeRate, tx }); + }, + + async send(req, res) { + await requirePin(req); + + let { user } = req; + let { address, memo, tx } = req.body; + let { hex, fee } = tx; + + if (config.bitcoin.walletpass) + await bc.walletPassphrase(config.bitcoin.walletpass, 300); + + ({ hex } = await bc.signRawTransactionWithWallet(hex)); + + let r = await bc.testMempoolAccept([hex]); + if (!r[0].allowed) fail("transaction rejected"); + + fee = sats(fee); + if (fee < 0) fail("fee cannot be negative"); + + tx = await bc.decodeRawTransaction(hex); + let { txid } = tx; + + let total = 0; + let change = 0; + + for (let { + scriptPubKey: { address }, + value + } of tx.vout) { + total += sats(value); + if ( + (await bc.getAddressInfo(address)).ismine && + !(await g(`invoice:${address}`)) + ) + change += sats(value); + } + + total = total - change + fee; + let amount = total - fee; + + await debit(txid, amount, fee, null, user, types.bitcoin, txid); + await bc.sendRawTransaction(hex); + + res.send({ txid }); } }; -- cgit v1.2.3