aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--db/models/proposals.js13
-rw-r--r--lib/account.js7
-rw-r--r--routes/assets.js2
-rw-r--r--routes/swaps.js741
-rw-r--r--routes/users.js3
5 files changed, 444 insertions, 322 deletions
diff --git a/db/models/proposals.js b/db/models/proposals.js
index 6d7ee40e..842101ac 100644
--- a/db/models/proposals.js
+++ b/db/models/proposals.js
@@ -56,7 +56,7 @@ const attributes = {
field: "a2"
},
v1: {
- type: DataTypes.INTEGER,
+ type: DataTypes.DOUBLE,
allowNull: true,
defaultValue: null,
primaryKey: false,
@@ -65,7 +65,7 @@ const attributes = {
field: "v1"
},
v2: {
- type: DataTypes.INTEGER,
+ type: DataTypes.DOUBLE,
allowNull: true,
defaultValue: null,
primaryKey: false,
@@ -73,6 +73,15 @@ const attributes = {
comment: null,
field: "v2"
},
+ rate: {
+ type: DataTypes.DOUBLE,
+ allowNull: true,
+ defaultValue: null,
+ primaryKey: false,
+ autoIncrement: false,
+ comment: null,
+ field: "rate"
+ },
text: {
type: DataTypes.TEXT,
allowNull: false,
diff --git a/lib/account.js b/lib/account.js
index 27ef830a..ca3ce7ea 100644
--- a/lib/account.js
+++ b/lib/account.js
@@ -1,11 +1,14 @@
const axios = require("axios");
-module.exports = async (asset, user) => {
+module.exports = async (asset, user, transaction) => {
const account = await db.Account.findOne({
where: {
user_id: user.id,
asset,
+ pubkey: null,
},
+ lock: transaction.LOCK.UPDATE,
+ transaction,
});
if (account) return account;
@@ -30,6 +33,8 @@ module.exports = async (asset, user) => {
},
order: [["id", "ASC"]],
limit: 1,
+ lock: transaction.LOCK.UPDATE,
+ transaction,
});
if (existing) {
diff --git a/routes/assets.js b/routes/assets.js
index 34856f04..b0115897 100644
--- a/routes/assets.js
+++ b/routes/assets.js
@@ -87,7 +87,6 @@ app.post(
params.asset_amount = asset_amount / (SATS / 10 ** precision);
- l.info("asset_amount", params.asset_amount);
if (token_amount) {
params.token_amount = token_amount;
params.token_address = token_address;
@@ -159,6 +158,7 @@ app.post(
);
emit(user.username, "account", account);
+ l.info("issued asset", user.username, params.asset_amount, ticker, name);
const asset_payment = await db.Payment.create(
{
diff --git a/routes/swaps.js b/routes/swaps.js
index f416ffc8..12cf72f9 100644
--- a/routes/swaps.js
+++ b/routes/swaps.js
@@ -5,15 +5,16 @@ const fs = require("fs");
const { spawn } = require("child_process");
const leveldb = level("leveldb");
const getAccount = require("../lib/account");
+const { Op } = require("sequelize");
const assets = {
b2e15d0d7a0c94e4e2ce0fe6e8691b9e451377f6e46e8045a86f7c4b5d4f0f23: "bitcoin",
- "4eebe36eb0819e6daa5dd3c97733251ff4eb728c810d949365d6dacaad5ef6e8": "tether",
+ "4eebe36eb0819e6daa5dd3c97733251ff4eb728c810d949365d6dacaad5ef6e8": "tether"
};
-const swapsdir = 'swaps/';
-if (!fs.existsSync(swapsdir)){
- fs.mkdirSync(swapsdir);
+const swapsdir = "swaps/";
+if (!fs.existsSync(swapsdir)) {
+ fs.mkdirSync(swapsdir);
}
const timeout = 20000;
@@ -37,15 +38,15 @@ const createProposal = (a1, v1, a2, v2) =>
);
const proc = cli("propose", a1, v1, a2, v2);
- proc.stdout.on("data", (data) => {
+ proc.stdout.on("data", data => {
resolve(data.toString());
});
- proc.stderr.on("error", (err) => {
+ proc.stderr.on("error", err => {
l.error("proposal error", err.toString());
reject(err.toString());
});
-
+
proc.on("close", (code, signal) => {
let msg = (code && code.toString()) || (signal && signal.toString());
reject(new Error(`Liquid swap tool process closed unexpectedly: ${msg}`));
@@ -56,18 +57,21 @@ const createProposal = (a1, v1, a2, v2) =>
reject(new Error(`Liquid swap tool process exited unexpectedly: ${msg}`));
});
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
+ setTimeout(
+ () => reject(new Error("Liquid swap tool timed out"), proc),
+ timeout
+ );
});
-const getInfo = (filename) =>
+const getInfo = filename =>
new Promise((resolve, reject) => {
const proc = cli("info", swapsdir + filename);
- proc.stdout.on("data", (data) => {
+ proc.stdout.on("data", data => {
resolve(data.toString());
});
- proc.stderr.on("data", (err) => {
+ proc.stderr.on("data", err => {
l.error("info error", err.toString());
reject(err.toString());
});
@@ -82,324 +86,419 @@ const getInfo = (filename) =>
reject(new Error(`Liquid swap tool process exited unexpectedly: ${msg}`));
});
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
- });
-
-app.delete("/proposal/:id", auth, ah(async (req, res) => {
- const { id } = req.params;
- await db.Proposal.destroy({
- where: {
- id,
- user_id: req.user.id,
- },
+ setTimeout(
+ () => reject(new Error("Liquid swap tool timed out"), proc),
+ timeout
+ );
});
- res.end();
-}));
-
-app.get("/proposal", auth, ah(async (req, res) => {
- try {
- const { user } = req;
- const { a1, v1, a2, v2 } = req.query;
- const b = await lq.getBalance();
- Object.keys(b).map((asset) => {
- assets[asset] = asset;
- });
- assets["ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"] = "tether";
- assets["6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d"] = "bitcoin";
- assets["a0c358a0f6947864af3a06f3f6a2aeb304df7fd95c922f2f22d7412399ce7691"] = "adamcoin";
-
- if (!assets[a1]) throw new Error("unsupported asset");
- if (v1 > b[assets[a1]]) throw new Error(`insufficient server funds, ${v1} ${b[assets[a1]]}`);
- const account = await db.Account.findOne({
+app.delete(
+ "/proposal/:id",
+ auth,
+ ah(async (req, res) => {
+ const { id } = req.params;
+ await db.Proposal.destroy({
where: {
- user_id: user.id,
- asset: a1,
- },
+ id,
+ user_id: req.user.id
+ }
});
- if (v1 > account.balance) throw new Error(`insufficient funds, ${v1} ${account.balance}`);
+ broadcast("removeProposal", id);
+ res.end();
+ })
+);
- l.info(
- `proposal requested to swap ${v1} ${assets[a1]} for ${v2} ${assets[a2]}`
- );
+app.get(
+ "/proposal",
+ auth,
+ ah(async (req, res) => {
+ try {
+ const { user } = req;
+ let { a1, v1, a2, v2 } = req.query;
+ const b = await lq.getBalance();
- let text = await createProposal(a1, v1, a2, v2);
- text = text.replace(/\s+/g, "").trim();
+ Object.keys(b).map(asset => {
+ assets[asset] = asset;
+ });
+ assets[config.liquid.btcasset] = "bitcoin";
+ assets[
+ "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
+ ] = "tether";
+ assets[
+ "a0c358a0f6947864af3a06f3f6a2aeb304df7fd95c922f2f22d7412399ce7691"
+ ] = "adamcoin";
- const proposal = await db.Proposal.create({
- a1,
- a2,
- v1: Math.round(v1 * SATS),
- v2: Math.round(v2 * SATS),
- user_id: user.id,
- text,
- });
+ if (!assets[a1]) throw new Error("unsupported asset");
+ if (parseFloat(v1) > parseFloat(b[assets[a1]]))
+ throw new Error(`insufficient server funds, ${v1} ${b[assets[a1]]}`);
- res.send({ proposal });
- } catch (e) {
- l.error(req.user.username, e.message);
- res.status(500).send({ error: e.message });
- }
-}));
+ await db.transaction(async transaction => {
+ const account = await db.Account.findOne({
+ where: {
+ user_id: user.id,
+ asset: a1
+ },
+ lock: transaction.LOCK.UPDATE,
+ transaction
+ });
-app.post("/accept", optionalAuth, ah(async (req, res) => {
- try {
- const { id, text } = req.body;
+ v1 = Math.round(v1 * SATS);
+ v2 = Math.round(v2 * SATS);
+ let rate = v2 / v1;
- const proposal = await db.Proposal.findOne({
- where: {
- id,
- accepted: false,
- },
- include: {
- model: db.User,
- as: "user",
- },
- });
+ if (v1 > account.balance)
+ throw new Error(`insufficient funds, ${v1} ${account.balance}`);
- if (!proposal) throw new Error("Proposal not found");
+ l.info(
+ `proposal requested to swap ${v1} ${assets[a1]} for ${v2} ${assets[a2]}`
+ );
- const filename = `proposal-${id}.txt`;
+ //let text = await createProposal(a1, v1, a2, v2);
+ //text = text.replace(/\s+/g, "").trim();
- fs.writeFileSync(swapsdir + filename, proposal.text);
- let info = JSON.parse(await getInfo(filename));
+ const proposals = await db.Proposal.findAll({
+ where: {
+ a1: a2,
+ a2: a1,
+ rate: { [Op.lte]: 1/rate },
+ accepted: false,
+ },
+ order: [["rate", "ASC"], ["id", "ASC"]]
+ });
- const { user } = req;
+ for (let i = 0; i < proposals.length; i++) {
+ if (!v1) break;
+ p = proposals[i];
+ if (p.v2 > v1) {
+ p.v2 -= v1;
+ await p.save();
+ broadcast("proposal", p);
+ v1 = 0;
+ } else {
+ v1 -= p.v2;
+ p.accepted = true;
+ await p.save();
+ broadcast("proposal", p);
+ }
+ }
- if (user) {
- let [fee, rate, asset] = parse(info);
- const leg1 = info.legs.find((leg) => !leg.incoming && leg.funded);
- const leg2 = info.legs.find((leg) => leg.incoming && !leg.funded);
- await db.transaction(async (transaction) => {
- const l1a1 = await getAccount(leg1.asset, user);
- const l1a2 = await getAccount(leg1.asset, proposal.user);
+ let proposal;
+ if (v1) {
+ proposal = await db.Proposal.create(
+ {
+ a1,
+ a2,
+ v1,
+ v2,
+ user_id: user.id
+ },
+ { transaction }
+ );
- let amount = Math.round(leg1.amount * SATS);
- if (amount > l1a2.balance)
- throw new Error(`Proposer has insufficient funds: ${amount}, ${l1a2.balance}`);
+ proposal.rate = v2 / v1;
+ broadcast("proposal", proposal);
+ }
- l1a1.balance += amount;
- l1a2.balance -= amount;
+ res.send({ proposal });
+ });
+ } catch (e) {
+ l.error(req.user.username, e.message, e.stack);
+ res.status(500).send(e.message);
+ }
+ })
+);
- let l1a1p = await db.Payment.create({
- hash: "Internal Transfer",
- amount,
- account_id: l1a1.id,
- memo: "Atomic Swap",
- user_id: user.id,
- currency: user.currency,
- rate,
- confirmed: true,
- received: true,
- network: "COINOS",
- });
+app.post(
+ "/accept",
+ optionalAuth,
+ ah(async (req, res) => {
+ try {
+ const { id, text } = req.body;
- let l1a2p = await db.Payment.create({
- hash: "Internal Transfer",
- amount: -amount,
- account_id: l1a2.id,
- memo: "Atomic Swap",
- user_id: proposal.user_id,
- currency: proposal.user.currency,
- rate,
- confirmed: true,
- received: false,
- network: "COINOS",
- });
+ const proposal = await db.Proposal.findOne({
+ where: {
+ id,
+ accepted: false
+ },
+ include: {
+ model: db.User,
+ as: "user"
+ }
+ });
- const l2a1 = await getAccount(leg2.asset, user);
- const l2a2 = await getAccount(leg2.asset, proposal.user);
+ if (!proposal) throw new Error("Proposal not found");
- amount = Math.round(leg2.amount * SATS);
- if (amount > l2a1.balance) throw new Error("Insufficient funds");
+ const filename = `proposal-${id}.txt`;
- l2a1.balance -= amount;
- l2a2.balance += amount;
+ fs.writeFileSync(swapsdir + filename, proposal.text);
+ let info = JSON.parse(await getInfo(filename));
- let l2a1p = await db.Payment.create({
- hash: "Internal Transfer",
- amount: -amount,
- account_id: l2a1.id,
- memo: "Atomic Swap",
- user_id: user.id,
- currency: user.currency,
- rate,
- confirmed: true,
- received: false,
- network: "COINOS",
- });
+ const { user } = req;
- let l2a2p = await db.Payment.create({
- hash: "Internal Transfer",
- amount,
- account_id: l2a2.id,
- memo: "Atomic Swap",
- user_id: proposal.user_id,
- currency: proposal.user.currency,
- rate,
- confirmed: true,
- received: true,
- network: "COINOS",
- });
+ if (user) {
+ let [fee, rate, asset] = parse(info);
+ const leg1 = info.legs.find(leg => !leg.incoming && leg.funded);
+ const leg2 = info.legs.find(leg => leg.incoming && !leg.funded);
+ await db.transaction(async transaction => {
+ const l1a1 = await getAccount(leg1.asset, user, transaction);
+ const l1a2 = await getAccount(leg1.asset, proposal.user, transaction);
- await l1a1.save({ transaction });
- await l1a2.save({ transaction });
- await l2a1.save({ transaction });
- await l2a2.save({ transaction });
+ let amount = Math.round(leg1.amount * SATS);
+ if (amount > l1a2.balance)
+ throw new Error(
+ `Proposer has insufficient funds: ${amount}, ${l1a2.balance}`
+ );
- proposal.accepted = true;
- await proposal.save({ transaction });
+ l1a1.balance += amount;
+ l1a2.balance -= amount;
- l1a1p = l1a1p.get({ plain: true });
- l1a1p.account = l1a1.get({ plain: true });
- l1a2p = l1a2p.get({ plain: true });
- l1a2p.account = l1a2.get({ plain: true });
- l2a1p = l2a1p.get({ plain: true });
- l2a1p.account = l2a1.get({ plain: true });
- l2a2p = l2a2p.get({ plain: true });
- l2a2p.account = l2a2.get({ plain: true });
+ let l1a1p = await db.Payment.create(
+ {
+ hash: "Internal Transfer",
+ amount,
+ account_id: l1a1.id,
+ memo: "Atomic Swap",
+ user_id: user.id,
+ currency: user.currency,
+ rate,
+ confirmed: true,
+ received: true,
+ network: "COINOS"
+ },
+ { transaction }
+ );
- emit(user.username, "account", l1a1);
- emit(user.username, "account", l2a1);
- emit(proposal.user.username, "account", l1a2);
- emit(proposal.user.username, "account", l2a2);
- emit(user.username, "payment", l1a1p);
- emit(user.username, "payment", l2a1p);
- emit(proposal.user.username, "payment", l1a2p);
- emit(proposal.user.username, "payment", l2a2p);
- emit(user.username, "proposal", proposal);
- emit(proposal.user.username, "proposal", proposal);
- });
- } else if (text) {
- const filename = `acceptance-${id}.txt`;
- fs.writeFileSync(swapsdir + filename, text);
+ let l1a2p = await db.Payment.create(
+ {
+ hash: "Internal Transfer",
+ amount: -amount,
+ account_id: l1a2.id,
+ memo: "Atomic Swap",
+ user_id: proposal.user_id,
+ currency: proposal.user.currency,
+ rate,
+ confirmed: true,
+ received: false,
+ network: "COINOS"
+ },
+ { transaction }
+ );
- info = JSON.parse(await getInfo(filename));
- let [fee, rate, asset] = parse(info);
- let { tx, u_address_p, u_address_r } = JSON.parse(
- Buffer.from(text, "base64").toString()
- );
- const sha256 = crypto.createHash("sha256");
- sha256.update(tx);
- const hash = sha256.digest("hex");
+ const l2a1 = await getAccount(leg2.asset, user);
+ const l2a2 = await getAccount(leg2.asset, proposal.user);
- const leg1 = info.legs.find((leg) => !leg.incoming);
- const leg2 = info.legs.find((leg) => leg.incoming);
+ amount = Math.round(leg2.amount * SATS);
+ if (amount > l2a1.balance) throw new Error("Insufficient funds");
- const l1a2 = await getAccount(leg1.asset, proposal.user);
- const btc = await getAccount(config.liquid.btcasset, proposal.user);
+ l2a1.balance -= amount;
+ l2a2.balance += amount;
- await db.transaction(async (transaction) => {
+ let l2a1p = await db.Payment.create(
+ {
+ hash: "Internal Transfer",
+ amount: -amount,
+ account_id: l2a1.id,
+ memo: "Atomic Swap",
+ user_id: user.id,
+ currency: user.currency,
+ rate,
+ confirmed: true,
+ received: false,
+ network: "COINOS"
+ },
+ { transaction }
+ );
- let amount = Math.round(leg1.amount * SATS);
- fee = Math.round(fee * SATS);
+ let l2a2p = await db.Payment.create(
+ {
+ hash: "Internal Transfer",
+ amount,
+ account_id: l2a2.id,
+ memo: "Atomic Swap",
+ user_id: proposal.user_id,
+ currency: proposal.user.currency,
+ rate,
+ confirmed: true,
+ received: true,
+ network: "COINOS"
+ },
+ { transaction }
+ );
- if (amount > l1a2.balance)
- throw new Error(`Proposer has insufficient funds: ${amount}, ${l1a2.balance}`);
+ await l1a1.save({ transaction });
+ await l1a2.save({ transaction });
+ await l2a1.save({ transaction });
+ await l2a2.save({ transaction });
- if (fee > btc.balance)
- throw new Error(`Proposer has insufficient funds for fee: ${fee}, ${btc.balance}`);
+ proposal.accepted = true;
+ await proposal.save({ transaction });
- l1a2.balance -= amount;
- btc.balance -= fee;
+ l1a1p = l1a1p.get({ plain: true });
+ l1a1p.account = l1a1.get({ plain: true });
+ l1a2p = l1a2p.get({ plain: true });
+ l1a2p.account = l1a2.get({ plain: true });
+ l2a1p = l2a1p.get({ plain: true });
+ l2a1p.account = l2a1.get({ plain: true });
+ l2a2p = l2a2p.get({ plain: true });
+ l2a2p.account = l2a2.get({ plain: true });
- let payment = await db.Payment.create({
- hash,
- amount: -amount,
- account_id: l1a2.id,
- fee,
- memo: "Atomic Swap",
- user_id: proposal.user_id,
- currency: proposal.user.currency,
- rate,
- address: u_address_r,
- confirmed: true,
- received: false,
- network: "liquid",
- });
-
- amount = Math.round(leg2.amount * SATS);
+ emit(user.username, "account", l1a1);
+ emit(user.username, "account", l2a1);
+ emit(proposal.user.username, "account", l1a2);
+ emit(proposal.user.username, "account", l2a2);
+ emit(user.username, "payment", l1a1p);
+ emit(user.username, "payment", l2a1p);
+ emit(proposal.user.username, "payment", l1a2p);
+ emit(proposal.user.username, "payment", l2a2p);
+ emit(user.username, "proposal", proposal);
- await db.Invoice.create({
- user_id: proposal.user_id,
- text: u_address_p,
- currency: proposal.user.currency,
- memo: "Atomic Swap",
- rate,
- amount,
- tip: 0,
- network: "liquid",
+ console.log("emitting", proposal.user.username, proposal);
+ emit(proposal.user.username, "proposal", proposal);
});
+ } else if (text) {
+ const filename = `acceptance-${id}.txt`;
+ fs.writeFileSync(swapsdir + filename, text);
- addresses[u_address_p] = proposal.user.username;
+ info = JSON.parse(await getInfo(filename));
+ let [fee, rate, asset] = parse(info);
+ let { tx, u_address_p, u_address_r } = JSON.parse(
+ Buffer.from(text, "base64").toString()
+ );
+ const sha256 = crypto.createHash("sha256");
+ sha256.update(tx);
+ const hash = sha256.digest("hex");
- await finalize(filename);
- await l1a2.save({ transaction });
- await btc.save({ transaction });
+ const leg1 = info.legs.find(leg => !leg.incoming);
+ const leg2 = info.legs.find(leg => leg.incoming);
- proposal.accepted = true;
- await proposal.save({ transaction });
+ await db.transaction(async transaction => {
+ const l1a2 = await getAccount(leg1.asset, proposal.user, transaction);
+ const bc = await getAccount(
+ config.liquid.btcasset,
+ proposal.user,
+ transaction
+ );
- payment = payment.get({ plain: true });
- payment.account = l1a2.get({ plain: true });
+ let amount = Math.round(leg1.amount * SATS);
+ fee = Math.round(fee * SATS);
- emit(proposal.user.username, "payment", payment);
- emit(proposal.user.username, "account", l1a2);
- emit(proposal.user.username, "account", btc);
- emit(proposal.user.username, "proposal", proposal);
- });
- } else {
- throw new Error("no acceptance provided");
- }
+ if (amount > l1a2.balance)
+ throw new Error(
+ `Proposer has insufficient funds: ${amount}, ${l1a2.balance}`
+ );
- res.send(info);
- } catch (e) {
- l.error(e.message);
- res.status(500).send(e.message);
- }
-}));
+ if (fee > btc.balance)
+ throw new Error(
+ `Proposer has insufficient funds for fee: ${fee}, ${btc.balance}`
+ );
-app.post("/acceptance", ah(async (req, res) => {
- const { acceptance: text } = req.body;
- l.info("acceptance received");
+ l1a2.balance -= amount;
+ btc.balance -= fee;
- fs.writeFile(swapsdir + "accepted.txt", text, async (err) => {
- if (err) {
- return res.status(500).send(err);
- }
+ let payment = await db.Payment.create({
+ hash,
+ amount: -amount,
+ account_id: l1a2.id,
+ fee,
+ memo: "Atomic Swap",
+ user_id: proposal.user_id,
+ currency: proposal.user.currency,
+ rate,
+ address: u_address_r,
+ confirmed: true,
+ received: false,
+ network: "liquid"
+ });
- try {
- let info = JSON.parse(
- await new Promise((resolve, reject) => {
- const proc = cli("info", swapsdir + "accepted.txt");
+ amount = Math.round(leg2.amount * SATS);
- proc.stdout.on("data", (data) => {
- resolve(data.toString());
+ await db.Invoice.create({
+ user_id: proposal.user_id,
+ text: u_address_p,
+ currency: proposal.user.currency,
+ memo: "Atomic Swap",
+ rate,
+ amount,
+ tip: 0,
+ network: "liquid"
});
- proc.stderr.on("data", (err) => {
- reject(err.toString());
- });
+ addresses[u_address_p] = proposal.user.username;
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
- })
- );
+ await finalize(filename);
+ await l1a2.save({ transaction });
+ await btc.save({ transaction });
- const time = Math.floor(new Date()).toString();
- const [fee, rate, asset] = parse(info);
- if (!asset) throw new Error("unsupported asset");
- l.info("accepted", info, rate, asset);
+ proposal.accepted = true;
+ await proposal.save({ transaction });
- leveldb.put(time, JSON.stringify({ text, info, rate, asset }));
- l.info({ text, info, rate, asset });
+ payment = payment.get({ plain: true });
+ payment.account = l1a2.get({ plain: true });
- res.send({ info, rate });
+ emit(proposal.user.username, "payment", payment);
+ emit(proposal.user.username, "account", l1a2);
+ emit(proposal.user.username, "account", btc);
+ emit(proposal.user.username, "proposal", proposal);
+ });
+ } else {
+ throw new Error("no acceptance provided");
+ }
+
+ res.send(info);
} catch (e) {
- l.error(e);
- res.status(500).send({ error: e });
+ l.error(e.message);
+ res.status(500).send(e.message);
}
- });
-}));
+ })
+);
+
+app.post(
+ "/acceptance",
+ ah(async (req, res) => {
+ const { acceptance: text } = req.body;
+ l.info("acceptance received");
+
+ fs.writeFile(swapsdir + "accepted.txt", text, async err => {
+ if (err) {
+ return res.status(500).send(err);
+ }
+
+ try {
+ let info = JSON.parse(
+ await new Promise((resolve, reject) => {
+ const proc = cli("info", swapsdir + "accepted.txt");
+
+ proc.stdout.on("data", data => {
+ resolve(data.toString());
+ });
+
+ proc.stderr.on("data", err => {
+ reject(err.toString());
+ });
+
+ setTimeout(
+ () => reject(new Error("Liquid swap tool timed out"), proc),
+ timeout
+ );
+ })
+ );
+
+ const time = Math.floor(new Date()).toString();
+ const [fee, rate, asset] = parse(info);
+ if (!asset) throw new Error("unsupported asset");
+ l.info("accepted", info, rate, asset);
+
+ leveldb.put(time, JSON.stringify({ text, info, rate, asset }));
+ l.info({ text, info, rate, asset });
+
+ res.send({ info, rate });
+ } catch (e) {
+ l.error(e);
+ res.status(500).send(e.message);
+ }
+ });
+ })
+);
checkQueue = async () => {
const ws = app.get("ws");
@@ -407,32 +506,32 @@ checkQueue = async () => {
leveldb
.createReadStream()
- .on("data", async function (data) {
+ .on("data", async function(data) {
txs.push({ ...JSON.parse(data.value), key: data.key });
})
- .on("end", async function (data) {
+ .on("end", async function(data) {
const rate = (a, b) => a.rate - b.rate;
const time = (a, b) => b.time - a.time;
- const pending = txs.filter((tx) => !tx.id);
- const completed = txs.filter((tx) => tx.id).sort(time);
+ const pending = txs.filter(tx => !tx.id);
+ const completed = txs.filter(tx => tx.id).sort(time);
const bitcoin = pending
- .filter((tx) => tx.asset === "bitcoin")
+ .filter(tx => tx.asset === "bitcoin")
.sort(rate)
.reverse();
const tether = pending
- .filter((tx) => tx.asset === "tether")
+ .filter(tx => tx.asset === "tether")
.sort(rate)
.reverse();
- const strip = (a) =>
+ const strip = a =>
a.map(({ id, key, info, rate, time }) => ({
id,
key,
info,
rate,
- time,
+ time
}));
ws &&
@@ -440,7 +539,7 @@ checkQueue = async () => {
JSON.stringify({
completed: strip(completed.slice(0, 3)),
bitcoin: strip(bitcoin.slice(0, 3)),
- tether: strip(tether.slice(0, 3)),
+ tether: strip(tether.slice(0, 3))
})
);
@@ -469,12 +568,12 @@ checkQueue = async () => {
});
};
-const parse = (info) => {
+const parse = info => {
const fee = info.legs[0].fee;
return [
fee,
(info.legs[1].amount / (info.legs[0].amount + fee)).toFixed(8),
- assets[info.legs[0].asset],
+ assets[info.legs[0].asset]
];
};
@@ -484,11 +583,11 @@ const finalize = (filename = "finalized.txt", text) => {
return new Promise((resolve, reject) => {
const proc = cli("finalize", swapsdir + filename, "-s");
- proc.stdout.on("data", (data) => {
+ proc.stdout.on("data", data => {
resolve(data.toString());
});
- proc.stderr.on("data", (err) => {
+ proc.stderr.on("data", err => {
reject(new Error(err.toString()));
});
@@ -502,39 +601,49 @@ const finalize = (filename = "finalized.txt", text) => {
reject(new Error(`Liquid swap tool process exited unexpectedly: ${msg}`));
});
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
+ setTimeout(
+ () => reject(new Error("Liquid swap tool timed out"), proc),
+ timeout
+ );
});
};
-app.get("/proposals", optionalAuth, ah(async (req, res) => {
- try {
- if (req.user) {
- res.send(await db.Proposal.findAll());
- } else {
- res.send(
- await db.Proposal.findAll({
- attributes: { exclude: ["user_id"] },
- where: {
- accepted: false,
- },
- })
- );
+app.get(
+ "/proposals",
+ optionalAuth,
+ ah(async (req, res) => {
+ try {
+ if (req.user) {
+ res.send(await db.Proposal.findAll());
+ } else {
+ res.send(
+ await db.Proposal.findAll({
+ attributes: { exclude: ["user_id"] },
+ where: {
+ accepted: false
+ }
+ })
+ );
+ }
+ } catch (e) {
+ res.status(500).send(e.message);
}
- } catch (e) {
- res.status(500).send(e.message);
- }
-}));
-
-app.post("/publish", auth, ah(async (req, res) => {
- try {
- const { id } = req.body;
- await db.Proposal.update(
- { public: true },
- { where: { id, user_id: req.user.id } }
- );
- res.end();
- } catch (e) {
- res.status(500).send(e.message);
- }
-}));
+ })
+);
+app.post(
+ "/publish",
+ auth,
+ ah(async (req, res) => {
+ try {
+ const { id } = req.body;
+ await db.Proposal.update(
+ { public: true },
+ { where: { id, user_id: req.user.id } }
+ );
+ res.end();
+ } catch (e) {
+ res.status(500).send(e.message);
+ }
+ })
+);
diff --git a/routes/users.js b/routes/users.js
index e92bc874..3d0b50e4 100644
--- a/routes/users.js
+++ b/routes/users.js
@@ -553,9 +553,8 @@ app.post(
l.info("user", user.username);
}
- let account = await getAccount(source.account.asset, user);
-
await db.transaction(async transaction => {
+ let account = await getAccount(source.account.asset, user, transaction);
let { hash, memo, confirmed, fee, network } = source;
source.redeemed = true;