aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--index.js3
-rw-r--r--lib/payments.js9
-rw-r--r--lib/utils.js1
-rw-r--r--routes/info.js2
-rw-r--r--routes/invoices.js1
-rw-r--r--routes/payments.js110
6 files changed, 110 insertions, 16 deletions
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;
+ 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 });
}
};