diff options
| author | Adam Soltys <[email protected]> | 2023-01-22 21:04:41 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2023-01-22 21:04:41 -0800 |
| commit | 2edcafb31e954628689e769c6926e3e48ddf84eb (patch) | |
| tree | df3c6bb06d9b56be9e64d6e851b3104593a63028 | |
| parent | 5dd47b9b2cb5a9359c57079205da68a675e10b45 (diff) | |
| download | coinos-server-2edcafb31e954628689e769c6926e3e48ddf84eb.tar.gz coinos-server-2edcafb31e954628689e769c6926e3e48ddf84eb.zip | |
on chain send
| -rw-r--r-- | index.js | 3 | ||||
| -rw-r--r-- | lib/payments.js | 9 | ||||
| -rw-r--r-- | lib/utils.js | 1 | ||||
| -rw-r--r-- | routes/info.js | 2 | ||||
| -rw-r--r-- | routes/invoices.js | 1 | ||||
| -rw-r--r-- | routes/payments.js | 110 |
6 files changed, 110 insertions, 16 deletions
@@ -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; + let { amount, hash, maxfee, name, memo, payreq, tip } = body; + + amount = parseInt(amount); + maxfee = parseInt(maxfee); + tip = parseInt(tip); + await requirePin({ body, user }); - let p = await debit(hash, amount, memo, user); + let p; + + if (payreq) { + p = await debit( + hash, + amount + maxfee, + maxfee, + memo, + user, + types.lightning + ); - if (hash) { + 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 }); } }; |
