diff options
| author | Adam Soltys <[email protected]> | 2020-10-09 10:04:27 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2020-10-09 10:06:02 -0700 |
| commit | d079d8c7c4c1efcb39f05255b2d025605dbbd790 (patch) | |
| tree | 4c2a30e7daf0f410b1b3e0829320fa48f29f41d9 /routes | |
| parent | 9a06c7883aec135b6d5243caa960d9cb9436b9c0 (diff) | |
| download | coinos-server-d079d8c7c4c1efcb39f05255b2d025605dbbd790.tar.gz coinos-server-d079d8c7c4c1efcb39f05255b2d025605dbbd790.zip | |
proposals -> orders
Diffstat (limited to 'routes')
| -rw-r--r-- | routes/swaps.js | 275 |
1 files changed, 202 insertions, 73 deletions
diff --git a/routes/swaps.js b/routes/swaps.js index 991c4abc..8872face 100644 --- a/routes/swaps.js +++ b/routes/swaps.js @@ -6,6 +6,8 @@ const { spawn } = require("child_process"); const leveldb = level("leveldb"); const getAccount = require("../lib/account"); const { Op, col } = require("sequelize"); +const uuidv4 = require("uuid/v4"); + const shallow = a => { let b = {}; for (x in a) { @@ -62,6 +64,62 @@ const getInfo = filename => ); }); +app.post( + "/propose", + auth, + ah(async (req, res) => { + const { a1, v1, a2, v2 } = req.body; + + const text = await new Promise((resolve, reject) => { + l.info( + "running liquid-cli tool %s %s %s %s %s", + config.liquid.conf, + a1, + v1, + a2, + v2 + ); + const proc = cli( + "propose", + a1, + (v1 / SATS).toFixed(8), + a2, + (v2 / SATS).toFixed(8) + ); + + proc.stdout.on("data", data => { + resolve(data.toString()); + }); + + proc.stderr.on("error", err => { + l.error("order 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}`) + ); + }); + + proc.on("exit", (code, signal) => { + let msg = (code && code.toString()) || (signal && signal.toString()); + reject( + new Error(`Liquid swap tool process exited unexpectedly: ${msg}`) + ); + }); + + setTimeout( + () => reject(new Error("Liquid swap tool timed out"), proc), + timeout + ); + }); + + res.send(text); + }) +); + const swap = async (user, { a1, a2, v1, v2 }) => { let rate = v2 / v1; @@ -114,7 +172,7 @@ const swap = async (user, { a1, a2, v1, v2 }) => { emit(user.username, "payment", payment.get({ plain: true })); emit(user.username, "account", a1acc.get({ plain: true })); - const proposals = await db.Proposal.findAll( + const orders = await db.Order.findAll( { where: { "$acc1.asset$": a2, @@ -144,9 +202,9 @@ const swap = async (user, { a1, a2, v1, v2 }) => { { transaction } ); - for (let i = 0; i < proposals.length; i++) { + for (let i = 0; i < orders.length; i++) { if (!v1) break; - p = proposals[i]; + p = orders[i]; if (p.v2 > v1) { p.v2 -= v1; await p.save({ transaction }); @@ -228,7 +286,7 @@ const swap = async (user, { a1, a2, v1, v2 }) => { p.a2 = p.acc2.asset; p.rate = p.v2 / p.v1; - broadcast("proposal", shallow(p)); + broadcast("order", shallow(p)); v1 = 0; } else { v1 -= p.v2; @@ -284,13 +342,13 @@ const swap = async (user, { a1, a2, v1, v2 }) => { p.a2 = p.acc2.asset; p.rate = p.v2 / p.v1; - broadcast("proposal", shallow(p)); + broadcast("order", shallow(p)); } } - let proposal; + let order; if (v1) { - proposal = await db.Proposal.create( + order = await db.Order.create( { v1, v2, @@ -301,19 +359,19 @@ const swap = async (user, { a1, a2, v1, v2 }) => { { transaction } ); - proposal = proposal.get({ plain: true }); - proposal.rate = v2 / v1; - proposal.a1 = a1; - proposal.a2 = a2; + order = order.get({ plain: true }); + order.rate = v2 / v1; + order.a1 = a1; + order.a2 = a2; - broadcast("proposal", proposal); + broadcast("order", order); } }); }; const cancel = async (user, id) => { await db.transaction(async transaction => { - let proposal = await db.Proposal.findOne( + let order = await db.Order.findOne( { where: { id, @@ -328,7 +386,7 @@ const cancel = async (user, id) => { { transaction } ); - let { acc1: account, v1, v2 } = proposal; + let { acc1: account, v1, v2 } = order; await account.increment({ balance: v1 }, { transaction }); await account.reload({ transaction }); @@ -351,13 +409,13 @@ const cancel = async (user, id) => { emit(user.username, "account", account.get({ plain: true })); emit(user.username, "payment", payment.get({ plain: true })); - if (proposal.fee) { + if (order.fee) { const btc = await getAccount(config.liquid.btcasset, user, transaction); payment = await db.Payment.create( { hash: "Swap Fee Refund", - amount: proposal.fee, + amount: order.fee, account_id: btc.id, user_id: user.id, currency: user.currency, @@ -369,20 +427,20 @@ const cancel = async (user, id) => { { transaction } ); - await btc.increment({ balance: proposal.fee }, { transaction }); + await btc.increment({ balance: order.fee }, { transaction }); await btc.reload({ transaction }); emit(user.username, "account", btc.get({ plain: true })); emit(user.username, "payment", payment.get({ plain: true })); } - broadcast("removeProposal", id); - await proposal.destroy({ transaction }); + broadcast("removeOrder", id); + await order.destroy({ transaction }); }); }; app.delete( - "/proposal/:id", + "/order/:id", auth, ah(async (req, res) => { const { id } = req.params; @@ -413,21 +471,9 @@ app.post( optionalAuth, ah(async (req, res) => { try { - const { id, text } = req.body; - - let proposal = await db.Proposal.findOne({ - where: { - id - }, - include: { - model: db.User, - as: "user" - } - }); - - if (!proposal) throw new Error("Proposal not found"); - + const { text } = req.body; const { user } = req; + const id = uuidv4(); if (text) { const filename = `acceptance-${id}.txt`; @@ -445,42 +491,123 @@ app.post( const leg1 = info.legs.find(leg => !leg.incoming); const leg2 = info.legs.find(leg => leg.incoming); + console.log(info, rate, leg2.amount / leg1.amount); + let orders = await db.Order.findAll({ + where: { + rate: { [Op.lte]: leg2.amount / leg1.amount }, + accepted: false, + "$acc1.asset$": leg1.asset, + "$acc2.asset$": leg2.asset + }, + attributes: { + include: [ + [col("acc1.asset"), "a1"], + [col("acc2.asset"), "a2"] + ] + }, + order: [["rate", "DESC"]], + include: [ + { + model: db.User, + as: "user", + }, + { + model: db.Account, + as: "acc1", + attributes: [] + }, + { + model: db.Account, + as: "acc2", + attributes: [] + } + ] + }); + + console.log(orders.map(p => ({ rate: p.rate, v1: p.v1, a1: p.a1 }))); + + let total = orders.reduce((a, b) => a + b.v1, 0); + let remaining = Math.round(leg1.amount * SATS); + if (total < remaining) + throw new Error("Not enough coins for sale at that price"); + await db.transaction(async transaction => { - const l2a2 = await getAccount(leg2.asset, proposal.user, transaction); + for (let i = 0; i < orders.length; i++) { + let order = orders[i]; + const account = await getAccount( + leg1.asset, + order.user, + transaction + ); - let amount = Math.round(leg1.amount * SATS); - fee = Math.round(fee * SATS); + console.log("aid", account.id); - amount = Math.round(leg2.amount * SATS); + let { v1: amount } = order; + if (remaining >= amount) { + console.log(remaining); + remaining -= amount; - await db.Invoice.create({ - user_id: proposal.user_id, - text: u_address_p, - address: u_address_p, - unconfidential: u_address_p, - currency: proposal.user.currency, - memo: "Atomic Swap", - rate: app.get("rates")[proposal.user.currency], - amount, - tip: 0, - network: "liquid", - account_id: l2a2.id - }); + await db.Invoice.create({ + user_id: order.user_id, + text: u_address_p, + address: u_address_p, + unconfidential: u_address_p, + currency: order.user.currency, + memo: "Atomic Swap", + rate: app.get("rates")[order.user.currency], + amount, + tip: 0, + network: "liquid", + account_id: account.id + }); - addresses[u_address_p] = proposal.user.username; + addresses[u_address_p] = order.user.username; - await finalize(filename); + order.accepted = true; + order.completedAt = new Date(); + await order.save({ transaction }); + + order = order.get({ plain: true }); + order.a1 = leg2.asset; + order.a2 = leg1.asset; + order.rate = order.v2 / order.v1; + + console.log("broadcasting", order.id); + + broadcast("order", shallow(order)); + } else { + await db.Invoice.create({ + user_id: order.user_id, + text: u_address_p, + address: u_address_p, + unconfidential: u_address_p, + currency: order.user.currency, + memo: "Atomic Swap", + rate: app.get("rates")[order.user.currency], + amount: remaining, + tip: 0, + network: "liquid", + account_id: account.id + }); - proposal.accepted = true; - proposal.completedAt = new Date(); - await proposal.save({ transaction }); + addresses[u_address_p] = order.user.username; - proposal = proposal.get({ plain: true }); - proposal.a1 = leg1.asset; - proposal.a2 = leg2.asset; - proposal.rate = proposal.v2 / proposal.v1; + console.log("new math", order.v2, Math.round(order.v2 * remaining / amount), amount, remaining, order.v1 - remaining); + order.decrement({ v1: remaining, v2: Math.round(order.v2 * remaining / amount) }, { transaction }); + await order.save({ transaction }); + await order.reload({ transaction }); - broadcast("proposal", shallow(proposal)); + order = order.get({ plain: true }); + order.a1 = leg2.asset; + order.a2 = leg1.asset; + order.rate = order.v2 / order.v1; + + broadcast("order", shallow(order)); + } + } + + console.log("finalizing", filename); + await finalize(filename); }); res.send(info); @@ -488,7 +615,7 @@ app.post( throw new Error("No acceptance provided"); } } catch (e) { - l.error(e.message); + l.error(e.message, e.stack); res.status(500).send(e.message); } }) @@ -651,11 +778,11 @@ const finalize = (filename = "finalized.txt", text) => { }; app.get( - "/proposals", + "/orders", optionalAuth, ah(async (req, res) => { try { - let proposals = await db.Proposal.findAll({ + let orders = await db.Order.findAll({ attributes: { include: [ [col("acc1.asset"), "a1"], @@ -677,7 +804,7 @@ app.get( }); res.send( - proposals.map(p => { + orders.map(p => { if (p.user_id !== req.user.id) p.user_id = null; return p; }) @@ -694,7 +821,7 @@ app.post( ah(async (req, res) => { try { const { id } = req.body; - await db.Proposal.update( + await db.Order.update( { public: true }, { where: { id, user_id: req.user.id } } ); @@ -720,7 +847,7 @@ setInterval(async () => { }); await db.transaction(async transaction => { - let p = await db.Proposal.findOne( + let p = await db.Order.findOne( { where: { user_id: user.id, @@ -750,7 +877,7 @@ setInterval(async () => { }; if (p) { - let bestBid = await db.Proposal.findOne( + let bestBid = await db.Order.findOne( { where: { "$acc1.asset$": lcad, @@ -775,7 +902,8 @@ setInterval(async () => { }, { transaction } ); - if (!bestBid || params.v2 / params.v1 > bestBid.rate) { + if (!bestBid || (params.v2 / params.v1 > bestBid.rate && p.acc2.balance >= params.v2)) { + p.v1 = params.v1; p.v2 = params.v2; await p.save(); p = p.get({ plain: true }); @@ -783,7 +911,7 @@ setInterval(async () => { p.a2 = params.a2; p.rate = p.v2 / p.v1; - broadcast("proposal", shallow(p)); + broadcast("order", shallow(p)); } } else { try { @@ -793,7 +921,7 @@ setInterval(async () => { } } - p = await db.Proposal.findOne( + p = await db.Order.findOne( { where: { user_id: user.id, @@ -822,15 +950,16 @@ setInterval(async () => { v2: amount * SATS }; - if (p) { + if (p && p.acc1.balance >= p.v1) { p.v1 = params.v1; + p.v2 = params.v2; await p.save(); p = p.get({ plain: true }); p.a1 = params.a1; p.a2 = params.a2; p.rate = p.v2 / p.v1; - broadcast("proposal", shallow(p)); + broadcast("order", shallow(p)); } else { try { await swap(user, params); |
