aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/buildtx.js76
1 files changed, 76 insertions, 0 deletions
diff --git a/lib/buildtx.js b/lib/buildtx.js
new file mode 100644
index 00000000..351f8081
--- /dev/null
+++ b/lib/buildtx.js
@@ -0,0 +1,76 @@
+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 ({ address, amount, feeRate, user }) => {
+ if (!feeRate) feeRate = (await bc.estimateSmartFee(6)).feerate * SATS;
+ feeRate = Math.round(feeRate / 1000);
+
+ const payments = await db.Payment.findAll({
+ where: {
+ received: true,
+ account_id: user.account_id,
+ }
+ });
+
+ const utxos = [];
+ for (let i = 0; i < payments.length; i++) {
+ try {
+ utxos.push(...(await axios.get(`${api}/address/${payments[i].address}/utxo`)).data);
+ } catch (e) {
+ l.error("problem fetching utxos", e.message);
+ }
+ }
+
+ let targets = [
+ {
+ address,
+ value: amount
+ }
+ ];
+
+ let { inputs, outputs, fee } = coinselect(utxos, targets, feeRate);
+
+ if (!inputs || !outputs) {
+ l.info("utxos", amount, feeRate, utxos, inputs, outputs);
+ throw new Error("Failed to create transaction");
+ }
+
+ let psbt = new bitcoin.Psbt({ network });
+ let total = 0;
+
+ outputs.map(({ address, value }) => {
+ total += value;
+ if (!address) {
+ address = payments[payments.length - 1].address;
+ change.push(address);
+ }
+
+ psbt = psbt.addOutput({
+ address,
+ 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();
+
+ l.info("returning", { tx: psbt, feeRate });
+ return { tx: psbt, feeRate };
+};