aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--index.js2
-rw-r--r--lib/rates.js2
-rw-r--r--package.json3
-rw-r--r--routes/bitcoin/sweep.js59
-rw-r--r--routes/payments.js1
-rw-r--r--routes/users.js2
-rw-r--r--yarn.lock7
7 files changed, 72 insertions, 4 deletions
diff --git a/index.js b/index.js
index 37e1b237..3b1c687f 100644
--- a/index.js
+++ b/index.js
@@ -7,6 +7,8 @@ const express = require("express");
l = require("pino")();
config = require("./config");
networks = [];
+prod = process.env.NODE_ENV === "production";
+
if (config.bitcoin) networks.push('bitcoin');
if (config.liquid) networks.push('liquid');
if (config.lna) networks.push('lightning');
diff --git a/lib/rates.js b/lib/rates.js
index b6c38a50..a8818375 100644
--- a/lib/rates.js
+++ b/lib/rates.js
@@ -6,7 +6,7 @@ let fetchRates;
(fetchRates = async () => {
let rates = require("./devrates");
- if (process.env.NODE_ENV === "production") {
+ if (prod) {
try {
let res = await axios.get(
`http://data.fixer.io/api/latest?access_key=${config.fixer}`
diff --git a/package.json b/package.json
index 045b9fcb..9a582d46 100644
--- a/package.json
+++ b/package.json
@@ -11,11 +11,12 @@
"axios": "^0.19.0",
"bcrypt": "^3.0.6",
"bitcoin-core": "https://github.com/asoltys/bitcoin-core",
- "bitcoinjs-lib": "^5.1.7",
+ "bitcoinjs-lib": "^5.1.8",
"body-parser": "^1.19.0",
"bolt11": "^1.2.5",
"buffer-reverse": "^1.0.1",
"clightning-client": "^0.1.2",
+ "coinselect": "^3.1.12",
"compression": "^1.7.4",
"connect-redis": "3.4.1",
"cookie-parser": "^1.4.4",
diff --git a/routes/bitcoin/sweep.js b/routes/bitcoin/sweep.js
new file mode 100644
index 00000000..37efb73f
--- /dev/null
+++ b/routes/bitcoin/sweep.js
@@ -0,0 +1,59 @@
+const axios = require("axios");
+const bitcoin = require("bitcoinjs-lib");
+const coinselect = require("coinselect");
+const split = require("coinselect/split");
+const api = prod ? "https://blockstream.info/api" : "http://localhost:3002";
+const SATS = 100000000;
+const network = prod
+ ? bitcoin.networks["bitcoin"]
+ : bitcoin.networks["regtest"];
+
+module.exports = async (req, res) => {
+ let ecpair = bitcoin.ECPair.fromWIF('cVosbTBiXp7LYSiGVRZfZnrEjpao4X4CUTG7Ze21XM3zFTLPCMvk', network);
+
+ let { address: from, amount, feeRate, target } = req.body;
+ let utxos;
+ if (!feeRate)
+ feeRate = ((await bc.estimateSmartFee(6)).feerate * SATS);
+ feeRate = Math.round(feeRate / 1000);
+ l.info("sweeping", req.user.username, from, amount, feeRate);
+ try {
+ ({ data: utxos } = await axios.get(`${api}/address/${from}/utxo`));
+ } catch (e) {
+ l.error("problem fetching utxos", e.message);
+ }
+
+ let targets = [
+ {
+ address: target,
+ value: amount
+ }
+ ];
+
+ let { inputs, outputs, fee } = coinselect(utxos, targets, feeRate);
+
+ if (!inputs || !outputs) return res.status(500).send("Unable to construct sweep transaction, try a lower fee rate?");
+
+ let psbt = new bitcoin.Psbt({ network });
+
+ outputs.map(({ address, value }) => {
+ psbt = psbt.addOutput({
+ address: address || from,
+ value
+ })
+ });
+
+ for (let i = 0; i < inputs.length; i++) {
+ let { txid, vout } = inputs[i];
+ let nonWitnessUtxo = Buffer.from(await bc.getRawTransaction(txid), 'hex');
+ psbt = psbt.addInput({
+ hash: txid,
+ index: vout,
+ nonWitnessUtxo,
+ });
+ }
+
+ feeRate = Math.round(feeRate * 1000);
+ psbt = psbt.toBase64();
+ res.send({ feeRate, psbt });
+};
diff --git a/routes/payments.js b/routes/payments.js
index ab35c9a0..9586a9a8 100644
--- a/routes/payments.js
+++ b/routes/payments.js
@@ -40,6 +40,7 @@ const { join } = require("path");
if (config.bitcoin) {
bc = new BitcoinCore(config.bitcoin);
+ app.post("/bitcoin/sweep", auth, require("./bitcoin/sweep"));
app.post("/bitcoin/fee", auth, require("./bitcoin/fee"));
app.post("/bitcoin/send", auth, require("./bitcoin/send"));
require("./bitcoin/receive");
diff --git a/routes/users.js b/routes/users.js
index 61421edf..4c39ca07 100644
--- a/routes/users.js
+++ b/routes/users.js
@@ -110,7 +110,7 @@ app.post("/register", async (req, res) => {
delete challenge[ip];
let success, score;
- if (process.env.NODE_ENV === "production") {
+ if (prod) {
if (!token) return res.status(500).send("Missing captcha token");
diff --git a/yarn.lock b/yarn.lock
index e4d05749..2530ca59 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -616,7 +616,7 @@ bitcoinjs-lib@^3.3.1:
varuint-bitcoin "^1.0.4"
wif "^2.0.1"
-bitcoinjs-lib@^5.1.7:
+bitcoinjs-lib@^5.1.8:
version "5.1.8"
resolved "https://registry.yarnpkg.com/bitcoinjs-lib/-/bitcoinjs-lib-5.1.8.tgz#b61be4fab7cf82142cea76f82e70a324c9a57984"
integrity sha512-LQQ9uw33sqW3K1aSzYCy0Az8zbcsR1ttaNkjThFwApT/vbB7bibEesPIxf0zvzjf8V8It68v7D/fCkjd4bStMw==
@@ -1005,6 +1005,11 @@ coininfo@^4.5.0:
dependencies:
safe-buffer "^5.1.1"
+coinselect@^3.1.12:
+ version "3.1.12"
+ resolved "https://registry.yarnpkg.com/coinselect/-/coinselect-3.1.12.tgz#2255794c4002f7ecac9cf6d1cefe9f0adfd2fe7f"
+ integrity sha512-XKnm9wwZzJRGuvR1BGNbFZEfa4SEr38do8Z5riq0797QwMT836EqhdPuhtbn8uAX8vCMqJ7+gS4CHa1G9M5xhw==
+
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"