aboutsummaryrefslogtreecommitdiffstats
path: root/routes/swaps.js
diff options
context:
space:
mode:
Diffstat (limited to 'routes/swaps.js')
-rw-r--r--routes/swaps.js799
1 files changed, 485 insertions, 314 deletions
diff --git a/routes/swaps.js b/routes/swaps.js
index 71c35733..9632d321 100644
--- a/routes/swaps.js
+++ b/routes/swaps.js
@@ -5,15 +5,31 @@ const fs = require("fs");
const { spawn } = require("child_process");
const leveldb = level("leveldb");
const getAccount = require("../lib/account");
+const { Swap, WatchOnlyWallet, fetchUtxos, networks } = require("tdex-sdk");
+const liquid = require("liquidjs-lib");
+const network = prod ? networks["liquid"] : networks["regtest"];
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);
+}
+
+function writeBinary(path, data) {
+ return new Promise((resolve, reject) => {
+ try {
+ const stream = fs.createWriteStream(path);
+ stream.write(data);
+ stream.end();
+ resolve();
+ } catch (err) {
+ reject(err);
+ }
+ });
}
const timeout = 20000;
@@ -37,15 +53,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 +72,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 +101,466 @@ 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");
- 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");
+ 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;
+ const { 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[
+ "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
+ ] = "tether";
+ assets[config.liquid.btcasset] = "bitcoin";
+ 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,
- });
+ l.info("a1", a1, assets);
+ if (!assets[a1]) throw new Error("unsupported asset");
+ if (v1 > b[assets[a1]]) throw new Error("insufficient server funds");
+ const account = await db.Account.findOne({
+ where: {
+ user_id: user.id,
+ asset: a1
+ }
+ });
+ if (v1 > account.balance) throw new Error("insufficient funds");
- res.send({ proposal });
- } catch (e) {
- l.error(e.message);
- res.status(500).send({ error: e.message });
- }
-}));
+ l.info(
+ `proposal requested to swap ${v1} ${assets[a1]} for ${v2} ${assets[a2]}`
+ );
-app.post("/accept", optionalAuth, ah(async (req, res) => {
- try {
- const { id, text } = req.body;
+ /*
+ let text = await createProposal(a1, v1, a2, v2);
+ text = text.replace(/\s+/g, "").trim();
+ */
- const proposal = await db.Proposal.findOne({
- where: {
- id,
- accepted: false,
- },
- include: {
- model: db.User,
- as: "user",
- },
- });
+ const woWallet = new WatchOnlyWallet({
+ address: (await lq.getAddressInfo(await lq.getNewAddress("", "bech32")))
+ .unconfidential,
+ network
+ });
- if (!proposal) throw new Error("Proposal not found");
+ let utxos = (
+ await lq.listUnspent(0, 9999999, [], false, { asset: a1 })
+ ).map(({ txid, vout, amount, asset }) => ({
+ txid,
+ vout,
+ value: Math.round(amount * SATS),
+ asset
+ }));
- const filename = `proposal-${id}.txt`;
+ const emptyPsbt = WatchOnlyWallet.createTx();
+ let psbtBase64 = woWallet.updateTx(
+ emptyPsbt,
+ utxos,
+ Math.round(v1 * SATS),
+ Math.round(v2 * SATS),
+ a1,
+ a2
+ );
- fs.writeFileSync(swapsdir + filename, proposal.text);
- let info = JSON.parse(await getInfo(filename));
+ let { Psbt } = liquid;
+ let psbtObj = Psbt.fromBase64(psbtBase64);
+ console.log(psbtBase64);
+ console.log("data", psbtObj.data);
+ psbtObj.data.outputs.map(o => {
+ console.log("output", o);
+ });
- const { user } = req;
+ const swap = new Swap();
+ const text = swap.request({
+ psbtBase64,
+ amountToBeSent: Math.round(v1 * SATS),
+ amountToReceive: Math.round(v2 * SATS),
+ assetToBeSent: a1,
+ assetToReceive: a2
+ });
- 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 filename = swapsdir + "swap_request.bin";
+ fs.writeFileSync(filename, text);
- let amount = Math.round(leg1.amount * SATS);
- if (amount > l1a2.balance)
- throw new Error(`Proposer has insufficient funds: ${amount}, ${l1a2.balance}`);
+ const proposal = await db.Proposal.create({
+ a1,
+ a2,
+ v1: Math.round(v1 * SATS),
+ v2: Math.round(v2 * SATS),
+ user_id: user.id,
+ text: text.toString()
+ });
- l1a1.balance += amount;
- l1a2.balance -= amount;
+ let swapRequest,
+ serializedSwapRequest,
+ walletInstance,
+ swapAccept,
+ swapAcceptFile;
- 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",
- });
+ serializedSwapRequest = await fs.readFileSync(filename);
+ const json = Swap.parse({
+ message: serializedSwapRequest,
+ type: "SwapRequest"
+ });
+ swapRequest = JSON.parse(json);
+ console.log(
+ `SwapRequest message: ${JSON.stringify(swapRequest, undefined, 2)}`
+ );
- 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 toWallet = new WatchOnlyWallet({
+ address: (await lq.getAddressInfo(await lq.getNewAddress("", "bech32")))
+ .unconfidential,
+ network
+ });
- const l2a1 = await getAccount(leg2.asset, user);
- const l2a2 = await getAccount(leg2.asset, proposal.user);
+ utxos = (await lq.listUnspent(0, 9999999, [], false, { asset: a2 })).map(
+ ({ txid, vout, amount, asset }) => ({
+ txid,
+ vout,
+ value: Math.round(amount * SATS),
+ asset
+ })
+ );
- amount = Math.round(leg2.amount * SATS);
- if (amount > l2a1.balance) throw new Error("Insufficient funds");
+ psbtBase64 = toWallet.updateTx(
+ swapRequest.transaction,
+ utxos,
+ Math.round(v2 * SATS),
+ Math.round(v1 * SATS),
+ a2,
+ a1
+ );
- l2a1.balance -= amount;
- l2a2.balance += amount;
+ const { btcasset: btc } = config.liquid;
- 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",
- });
+ psbtObj = Psbt.fromBase64(swapRequest.transaction);
+ console.log("data", psbtObj.data);
+ psbtObj.data.outputs.map(o => {
+ console.log("output", o);
+ });
+ psbtObj.addOutput({
+ asset: btc,
+ script: Buffer.alloc(0),
+ value: 1000,
+ nonce: Buffer.alloc(1, 0)
+ });
- 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",
- });
+ let { psbt } = await lq.walletSignPsbt(psbtObj.toBase64());
+ let tx = await lq.finalizePsbt(psbt);
+ console.log(tx);
+ await lq.sendRawTransaction(tx.hex);
- await l1a1.save({ transaction });
- await l1a2.save({ transaction });
- await l2a1.save({ transaction });
- await l2a2.save({ transaction });
+ // toWallet.sign(psbtBase64);
- proposal.accepted = true;
- await proposal.save({ transaction });
+ throw new Error("boo");
- 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 });
+ res.send({ proposal });
+ } catch (e) {
+ l.error(e.message);
+ throw e;
+ res.status(500).send({ error: e.message });
+ }
+ })
+);
+
+app.post(
+ "/accept",
+ optionalAuth,
+ ah(async (req, res) => {
+ try {
+ const { id, text } = req.body;
- 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);
+ const proposal = await db.Proposal.findOne({
+ where: {
+ id,
+ accepted: false
+ },
+ include: {
+ model: db.User,
+ as: "user"
+ }
});
- } else if (text) {
- const filename = `acceptance-${id}.txt`;
- fs.writeFileSync(swapsdir + filename, text);
- 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");
+ if (!proposal) throw new Error("Proposal not found");
- const leg1 = info.legs.find((leg) => !leg.incoming);
- const leg2 = info.legs.find((leg) => leg.incoming);
+ const filename = `proposal-${id}.txt`;
- const l1a2 = await getAccount(leg1.asset, proposal.user);
- const btc = await getAccount(config.liquid.btcasset, proposal.user);
+ fs.writeFileSync(swapsdir + filename, proposal.text);
+ let info = JSON.parse(await getInfo(filename));
- await db.transaction(async (transaction) => {
+ const { user } = req;
- let amount = Math.round(leg1.amount * SATS);
- fee = Math.round(fee * SATS);
+ 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);
- if (amount > l1a2.balance)
- throw new Error(`Proposer has insufficient funds: ${amount}, ${l1a2.balance}`);
+ let amount = Math.round(leg1.amount * SATS);
+ if (amount > l1a2.balance)
+ throw new Error(
+ `Proposer has insufficient funds: ${amount}, ${l1a2.balance}`
+ );
- if (fee > btc.balance)
- throw new Error(`Proposer has insufficient funds for fee: ${fee}, ${btc.balance}`);
+ l1a1.balance += amount;
+ l1a2.balance -= amount;
- l1a2.balance -= amount;
- btc.balance -= fee;
+ 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"
+ });
- 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: "LBTC",
- });
+ 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"
+ });
- amount = Math.round(leg2.amount * SATS);
+ const l2a1 = await getAccount(leg2.asset, user);
+ const l2a2 = await getAccount(leg2.asset, proposal.user);
- 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: "LBTC",
- });
+ amount = Math.round(leg2.amount * SATS);
+ if (amount > l2a1.balance) throw new Error("Insufficient funds");
- addresses[u_address_p] = proposal.user.username;
+ l2a1.balance -= amount;
+ l2a2.balance += amount;
- await finalize(filename);
- await l1a2.save({ transaction });
- await btc.save({ 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"
+ });
- proposal.accepted = true;
- await proposal.save({ transaction });
+ 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"
+ });
- payment = payment.get({ plain: true });
- payment.account = l1a2.get({ plain: true });
+ await l1a1.save({ transaction });
+ await l1a2.save({ transaction });
+ await l2a1.save({ transaction });
+ await l2a2.save({ transaction });
- 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");
- }
+ proposal.accepted = true;
+ await proposal.save({ transaction });
- res.send(info);
- } catch (e) {
- l.error(e.message);
- res.status(500).send(e.message);
- }
-}));
+ 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 });
-app.post("/acceptance", ah(async (req, res) => {
- const { acceptance: text } = req.body;
- l.info("acceptance received");
+ 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);
- fs.writeFile(swapsdir + "accepted.txt", text, async (err) => {
- if (err) {
- return res.status(500).send(err);
- }
+ 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");
- try {
- let info = JSON.parse(
- await new Promise((resolve, reject) => {
- const proc = cli("info", swapsdir + "accepted.txt");
+ const leg1 = info.legs.find(leg => !leg.incoming);
+ const leg2 = info.legs.find(leg => leg.incoming);
+
+ const l1a2 = await getAccount(leg1.asset, proposal.user);
+ const btc = await getAccount(config.liquid.btcasset, proposal.user);
+
+ await db.transaction(async transaction => {
+ let amount = Math.round(leg1.amount * SATS);
+ fee = Math.round(fee * SATS);
+
+ if (amount > l1a2.balance)
+ throw new Error(
+ `Proposer has insufficient funds: ${amount}, ${l1a2.balance}`
+ );
+
+ if (fee > btc.balance)
+ throw new Error(
+ `Proposer has insufficient funds for fee: ${fee}, ${btc.balance}`
+ );
+
+ l1a2.balance -= amount;
+ btc.balance -= fee;
- proc.stdout.on("data", (data) => {
- resolve(data.toString());
+ 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: "LBTC"
});
- proc.stderr.on("data", (err) => {
- reject(err.toString());
+ amount = Math.round(leg2.amount * SATS);
+
+ 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: "LBTC"
});
- setTimeout(() => reject(new Error("Liquid swap tool timed out"), proc), timeout);
- })
- );
+ addresses[u_address_p] = proposal.user.username;
+
+ 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 });
+
+ 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, rate });
+ 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({ error: e });
+ }
+ });
+ })
+);
checkQueue = async () => {
const ws = app.get("ws");
@@ -407,32 +568,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 +601,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 +630,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 +645,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 +663,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);
+ }
+ })
+);