aboutsummaryrefslogtreecommitdiffstats
path: root/routes
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2020-08-16 21:34:13 -0700
committerAdam Soltys <[email protected]>2020-08-16 21:34:13 -0700
commit7ab3036cb1576fe38ba1fd423a58b7cd97a58579 (patch)
tree305b1a0aa321389b60385009876bbdb1fe0a1c68 /routes
parentb2208797d3c5559c7e8cc7d35b7a020da0c61193 (diff)
downloadcoinos-server-7ab3036cb1576fe38ba1fd423a58b7cd97a58579.tar.gz
coinos-server-7ab3036cb1576fe38ba1fd423a58b7cd97a58579.zip
non-custodial liquid wallets
Diffstat (limited to 'routes')
-rw-r--r--routes/bitcoin/broadcast.js3
-rw-r--r--routes/bitcoin/receive.js22
-rw-r--r--routes/invoices.js1
-rw-r--r--routes/liquid/broadcast.js36
-rw-r--r--routes/liquid/fee.js19
-rw-r--r--routes/liquid/receive.js134
-rw-r--r--routes/liquid/send.js7
-rw-r--r--routes/payments.js22
-rw-r--r--routes/swaps.js1
-rw-r--r--routes/users.js13
10 files changed, 172 insertions, 86 deletions
diff --git a/routes/bitcoin/broadcast.js b/routes/bitcoin/broadcast.js
index c7b134ac..4324e0d9 100644
--- a/routes/bitcoin/broadcast.js
+++ b/routes/bitcoin/broadcast.js
@@ -19,12 +19,13 @@ module.exports = ah(async (req, res) => {
network: "BTC",
});
- account.balance -= payment.amount + payment.fee;
+ account.balance += payment.amount - payment.fee;
await account.save();
payment = payment.get({ plain: true });
payment.account = account.get({ plain: true });
emit(user.username, "payment", payment);
+ emit(user.username, "account", payment.account);
res.send(payment);
} else {
res.send(result);
diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js
index ec120605..987f5079 100644
--- a/routes/bitcoin/receive.js
+++ b/routes/bitcoin/receive.js
@@ -1,6 +1,7 @@
const reverse = require("buffer-reverse");
const zmq = require("zeromq");
const { Op } = require("sequelize");
+const { fromBase58 } = require("bip32");
const bitcoin = require("bitcoinjs-lib");
@@ -35,7 +36,10 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
return;
}
- if (Object.keys(addresses).includes(address) && !change.includes(address)) {
+ if (
+ Object.keys(addresses).includes(address) &&
+ !change.includes(address)
+ ) {
payments.push(hash);
let user = await db.User.findOne({
@@ -55,7 +59,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
const currency = invoice ? invoice.currency : user.currency;
const rate = invoice ? invoice.rate : app.get("rates")[user.currency];
const tip = invoice ? invoice.tip : 0;
- const memo = invoice ? invoice.memo : '';
+ const memo = invoice ? invoice.memo : "";
let confirmed = false;
@@ -66,7 +70,19 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
},
});
- let account = accounts.find(a => a.address === address);
+ let account = accounts.find(({ index, pubkey }) => {
+ const { payments } = bitcoin;
+ index &&
+ pubkey &&
+ address ===
+ payments.p2wpkh({
+ pubkey: fromBase58(pubkey, network).derivePath(
+ `${index}`
+ ).publicKey,
+ network,
+ }).address;
+ });
+
if (!account) account = accounts[0];
account.pending += value;
diff --git a/routes/invoices.js b/routes/invoices.js
index ba4da254..511d6c02 100644
--- a/routes/invoices.js
+++ b/routes/invoices.js
@@ -26,6 +26,7 @@ app.post("/invoice", ah(async (req, res, next) => {
}
if (!user) throw new Error("user not provided");
invoice.user_id = user.id;
+ invoice.account_id = user.account_id;
l.info(
"creating invoice",
diff --git a/routes/liquid/broadcast.js b/routes/liquid/broadcast.js
new file mode 100644
index 00000000..e3709597
--- /dev/null
+++ b/routes/liquid/broadcast.js
@@ -0,0 +1,36 @@
+module.exports = ah(async (req, res) => {
+ try {
+ const { user } = req;
+ let hash = await lq.sendRawTransaction(req.body.tx);
+
+ if (user) {
+ let { account } = user;
+ let payment = await db.Payment.create({
+ ...req.body.payment,
+ hash,
+ amount: -req.body.payment.amount,
+ tip: 0,
+ account_id: account.id,
+ user_id: user.id,
+ rate: app.get("rates")[user.currency],
+ currency: user.currency,
+ confirmed: true,
+ received: false,
+ network: "LBTC",
+ });
+
+ account.balance += payment.amount - payment.fee;
+ await account.save();
+
+ payment = payment.get({ plain: true });
+ payment.account = account.get({ plain: true });
+ emit(user.username, "payment", payment);
+ emit(user.username, "account", payment.account);
+ res.send(payment);
+ } else {
+ res.send(result);
+ }
+ } catch (e) {
+ res.status(500).send(e.message);
+ }
+});
diff --git a/routes/liquid/fee.js b/routes/liquid/fee.js
index 77a9ce17..acf28160 100644
--- a/routes/liquid/fee.js
+++ b/routes/liquid/fee.js
@@ -1,8 +1,20 @@
+const buildTx = require("../../lib/buildliquidtx");
+
module.exports = ah(async (req, res) => {
let { user } = req;
let { address, asset, amount, feeRate } = req.body;
let tx, fee;
+ if (user.account.pubkey) {
+ try {
+ let psbt = await buildTx({ address, asset, amount, feeRate, user });
+ return res.send(psbt);
+ } catch(e) {
+ throw e;
+ return res.status(500).send(e.message);
+ }
+ }
+
let invoice = await db.Invoice.findOne({
where: { address },
include: {
@@ -13,8 +25,11 @@ module.exports = ah(async (req, res) => {
});
if (invoice) {
- emit(user.username, "to", invoice.user);
- return res.end();
+ let { ismine } = await lq.getAddressInfo(address);
+ if (ismine) {
+ emit(user.username, "to", invoice.user);
+ return res.end();
+ }
}
try {
diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js
index 3fe235a6..325e6783 100644
--- a/routes/liquid/receive.js
+++ b/routes/liquid/receive.js
@@ -1,7 +1,53 @@
const axios = require("axios");
+const reverse = require("buffer-reverse");
const zmq = require("zeromq");
const { Op } = require("sequelize");
+const { fromBase58 } = require("bip32");
+const bitcoin = require("bitcoinjs-lib");
const elements = require("elementsjs-lib");
+const liquid = require("liquidjs-lib");
+
+const network =
+ liquid.networks[
+ config.liquid.network === "mainnet" ? "liquid" : config.liquid.network
+ ];
+
+const getAccount = async (params, pending) => {
+ let account = await db.Account.findOne({
+ where: params
+ });
+
+ if (account) return account;
+
+ let { asset } = params;
+ let name = asset.substr(0, 6);
+ let domain = "";
+ let ticker = asset.substr(0, 3).toUpperCase();
+ let precision = 8;
+
+ const assets = (await axios.get("https://assets.blockstream.info/")).data;
+
+ if (assets[asset]) {
+ ({ domain, ticker, precision, name } = assets[asset]);
+ } else {
+ const existing = await db.Account.findOne({
+ where: {
+ asset,
+ },
+ order: [["id", "ASC"]],
+ limit: 1,
+ });
+
+ if (existing) {
+ ({ domain, ticker, precision, name } = existing);
+ }
+ }
+
+ params = { ...params, ...{ domain, ticker, precision, name } };
+ params.balance = 0;
+ params.pending = pending;
+ return db.Account.create(params);
+};
const zmqRawBlock = zmq.socket("sub");
zmqRawBlock.connect(config.liquid.zmqrawblock);
@@ -26,77 +72,50 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
const value = toSats(o.value);
const address = o.scriptPubKey.addresses[0];
- if (Object.keys(addresses).includes(address)) {
+ if (
+ Object.keys(addresses).includes(address) &&
+ !change.includes(address)
+ ) {
let user = await getUser(addresses[address]);
- let confirmed = 0;
+ let invoice = await db.Invoice.findOne({
+ where: {
+ address,
+ user_id: user.id,
+ network: "LBTC",
+ },
+ order: [["id", "DESC"]],
+ include: {
+ model: db.Account,
+ as: "account",
+ },
+ });
- let params = {
- user_id: user.id,
- asset,
- };
+ if (!invoice) return;
- let account = await db.Account.findOne({
- where: params,
- });
+ let confirmed = 0;
- if (account) {
+ let { account } = invoice;
+
+ if (account.asset === asset) {
account.pending += value;
await account.save();
} else {
- let name = asset.substr(0, 6);
- let domain = '';
- let ticker = asset.substr(0, 3).toUpperCase();
- let precision = 8;
-
- const assets = (await axios.get("https://assets.blockstream.info/"))
- .data;
-
- if (assets[asset]) {
- ({ domain, ticker, precision, name } = assets[asset]);
- } else {
- const existing = await db.Account.findOne({
- where: {
- asset,
- },
- order: [["id", "ASC"]],
- limit: 1,
- });
-
- if (existing) {
- ({ domain, ticker, precision, name } = existing);
- }
- }
-
- params = { ...params, ...{ domain, ticker, precision, name } };
- params.balance = 0;
- params.pending = value;
- account = await db.Account.create(params);
+ if (!account) account = await getAccount(
+ {
+ user_id: user.id,
+ asset,
+ pubkey: account.pubkey,
+ },
+ value
+ );
}
if (config.liquid.walletpass)
await lq.walletPassphrase(config.liquid.walletpass, 300);
- user.confidential = await lq.getNewAddress();
- user.liquid = (
- await lq.getAddressInfo(user.confidential)
- ).unconfidential;
-
await user.save();
- addresses[user.liquid] = user.username;
-
- let invoice;
- if (asset === config.liquid.btcasset) {
- invoice = await db.Invoice.findOne({
- where: {
- user_id: user.id,
- network: "LBTC",
- },
- order: [["id", "DESC"]],
- });
- }
-
const currency = invoice ? invoice.currency : user.currency;
const rate = invoice ? invoice.rate : app.get("rates")[user.currency];
const tip = invoice ? invoice.tip : 0;
@@ -123,7 +142,7 @@ zmqRawTx.on("message", async (topic, message, sequence) => {
emit(user.username, "payment", payment);
emit(user.username, "account", account);
- l.info("liquid detected", user.username, asset, value);
+ l.info("liquid detected", address, user.username, asset, value);
notify(user, `${value} SAT payment detected`);
}
})
@@ -218,6 +237,7 @@ zmqRawBlock.on("message", async (topic, message, sequence) => {
});
setInterval(async () => {
+ // throw new Error("boom");
try {
const arr = Object.keys(queue);
diff --git a/routes/liquid/send.js b/routes/liquid/send.js
index 1d12db30..7f7e1cb5 100644
--- a/routes/liquid/send.js
+++ b/routes/liquid/send.js
@@ -39,8 +39,9 @@ module.exports = ah(async (req, res) => {
await db.transaction(async (transaction) => {
for (let i = 0; i < assets.length; i++) {
let asset = assets[i];
- let total = totals[asset];
- if (change[asset]) total -= change[asset];
+ let amount = totals[asset];
+ if (change[asset]) amount -= change[asset];
+ let total = amount;
if (asset === config.liquid.btcasset) total += fee;
l.info("creating liquid payment", user.username, asset, total, fee);
@@ -67,7 +68,7 @@ module.exports = ah(async (req, res) => {
await account.save({ transaction });
let payment = {
- amount: -total,
+ amount: -amount,
account_id: account.id,
fee,
memo,
diff --git a/routes/payments.js b/routes/payments.js
index ca479026..5e7263da 100644
--- a/routes/payments.js
+++ b/routes/payments.js
@@ -18,19 +18,12 @@ ah(async () => {
l.warn("couldn't read exceptions file", e.message);
}
- await db.User.findAll({
- attributes: ["username", "address", "liquid"],
- }).map((u) => {
- if (u.address) addresses[u.address] = u.username;
- if (u.liquid) addresses[u.liquid] = u.username;
- });
-
- await db.Invoice.findAll({
+ (await db.Invoice.findAll({
include: {
model: db.User,
as: "user",
},
- }).map(({ address, user, unconfidential }) => {
+ })).map(({ address, user, unconfidential }) => {
if (address && user) addresses[address] = user.username;
if (unconfidential && user) addresses[unconfidential] = user.username;
});
@@ -113,7 +106,11 @@ ah(async () => {
if (config.bitcoin) {
bc = new BitcoinCore(config.bitcoin);
- app.post("/bitcoin/broadcast", optionalAuth, require("./bitcoin/broadcast"));
+ app.post(
+ "/bitcoin/broadcast",
+ optionalAuth,
+ require("./bitcoin/broadcast")
+ );
app.get("/bitcoin/generate", auth, require("./bitcoin/generate"));
app.post("/bitcoin/sweep", auth, require("./bitcoin/sweep"));
app.post("/bitcoin/fee", auth, require("./bitcoin/fee"));
@@ -123,6 +120,11 @@ ah(async () => {
if (config.liquid) {
lq = new BitcoinCore(config.liquid);
+ app.post(
+ "/liquid/broadcast",
+ optionalAuth,
+ require("./liquid/broadcast")
+ );
app.get("/liquid/generate", auth, require("./liquid/generate"));
app.post("/liquid/fee", auth, require("./liquid/fee"));
app.post("/liquid/send", auth, require("./liquid/send"));
diff --git a/routes/swaps.js b/routes/swaps.js
index 733e261f..71c35733 100644
--- a/routes/swaps.js
+++ b/routes/swaps.js
@@ -408,7 +408,6 @@ checkQueue = async () => {
leveldb
.createReadStream()
.on("data", async function (data) {
- console.log("pushing", data.key);
txs.push({ ...JSON.parse(data.value), key: data.key });
})
.on("end", async function (data) {
diff --git a/routes/users.js b/routes/users.js
index ececd37b..58738b72 100644
--- a/routes/users.js
+++ b/routes/users.js
@@ -157,10 +157,6 @@ app.post(
sockets[username] = sockets[user.username];
user.username = username;
- if (user.address) addresses[user.address] = username;
-
- if (user.liquid) addresses[user.liquid] = user.username;
-
token = jwt.sign({ username }, config.jwt);
res.cookie("token", token, {
expires: new Date(Date.now() + 432000000),
@@ -223,17 +219,16 @@ app.post(
"/accounts",
auth,
ah(async (req, res) => {
- const { address, pubkey } = req.body;
+ const { name, pubkey, ticker } = req.body;
const { user } = req;
let account = await db.Account.create({
- address,
user_id: user.id,
asset: config.liquid.btcasset,
balance: 0,
pending: 0,
- name: "Bitcoin",
- ticker: "BTC",
+ name,
+ ticker,
precision: 8,
pubkey,
});
@@ -375,7 +370,7 @@ app.post(
const account = await db.Account.findOne({
where: { id },
- });
+ });
emit(user.username, "account", account);
res.end();