diff options
| author | Gyulai Zoltan <[email protected]> | 2021-09-28 16:51:35 +0300 |
|---|---|---|
| committer | Gyulai Zoltan <[email protected]> | 2021-09-28 16:51:35 +0300 |
| commit | 5f949a00ab98792db22bb5ab0104a06c714932f2 (patch) | |
| tree | ea936c9499192758d521f8f61b0d85f8844cbafa | |
| parent | ed3482fc15d3d8f8e8b3bceff7d473fd29601280 (diff) | |
| download | coinos-server-5f949a00ab98792db22bb5ab0104a06c714932f2.tar.gz coinos-server-5f949a00ab98792db22bb5ab0104a06c714932f2.zip | |
feat: added liquid withdrawal
| -rw-r--r-- | lib/feeliquidtx.js | 13 | ||||
| -rw-r--r-- | routes/liquid/send.js | 77 | ||||
| -rw-r--r-- | routes/liquid/util/decrementacc.js | 86 | ||||
| -rw-r--r-- | routes/liquid/withdraw.js | 35 | ||||
| -rw-r--r-- | routes/payments.js | 1 |
5 files changed, 138 insertions, 74 deletions
diff --git a/lib/feeliquidtx.js b/lib/feeliquidtx.js new file mode 100644 index 00000000..d32623ab --- /dev/null +++ b/lib/feeliquidtx.js @@ -0,0 +1,13 @@ +module.exports = async (txid) => { + const tx = await lq.getRawTransaction(txid); + const transaction = await lq.decodeRawTransaction(tx); + let valueOut = 0; + + transaction.vout.forEach(o => { + if (o.scriptPubKey.type === 'fee') { + valueOut = o.value; + } + }); + + return toSats(valueOut); +} diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 0c0b2012..6df430de 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -1,6 +1,7 @@ const btc = config.liquid.btcasset; const lcad = config.liquid.cadasset; const { Transaction } = require("@asoltys/liquidjs-lib"); +const decrementAccount = require('./util/decrementacc'); sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { l.info("sending liquid", amount, address); @@ -54,81 +55,9 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { let asset = assets[i]; let amount = totals[asset]; if (change[asset]) amount -= change[asset]; - let total = amount; - if (asset === btc) { - let covered = 0; - let nonbtc = assets.filter(a => a !== btc); - if (nonbtc.length === 1) { - let faucet = await db.Account.findOne({ - where: { - asset: nonbtc[0], - user_id: null - }, - lock: transaction.LOCK.UPDATE, - transaction - }); - - if (faucet) { - covered = faucet.balance; - if (covered > fee) covered = fee; - await faucet.decrement({ balance: covered }, { transaction }); - await faucet.reload({ transaction }); - await faucet.save({ transaction }); - } - } - - total += fee - covered; - } - - if (limit && total > limit + fee) - throw new Error("Tx amount exceeds authorized amount"); - - if (asset !== btc || total) { - l.info("creating liquid payment", user.username, asset, total, fee); - - let account = await db.Account.findOne({ - where: { - user_id: user.id, - asset, - pubkey: null - }, - lock: transaction.LOCK.UPDATE, - order: [["balance", "DESC"]], - transaction - }); - - if (total > account.balance) { - l.warn("amount exceeds balance", { - total, - fee, - balance: account.balance - }); - throw new Error( - `Insufficient funds, need ${total} ${ - account.ticker === "BTC" ? "SAT" : account.ticker - }, have ${account.balance}` - ); - } - - await account.decrement({ balance: total }, { transaction }); - await account.reload({ transaction }); - - let payment = { - amount: -amount, - account_id: account.id, - fee, - memo, - user_id: user.id, - rate: app.get("rates")[user.currency], - currency: user.currency, - address, - confirmed: true, - received: false, - network: "liquid" - }; - - payment.account = account; + const payment = await decrementAccount(user, transaction, limit, fee, assets, amount, address, memo, asset); + if(payment) { payments.push(payment); } } diff --git a/routes/liquid/util/decrementacc.js b/routes/liquid/util/decrementacc.js new file mode 100644 index 00000000..5be30e13 --- /dev/null +++ b/routes/liquid/util/decrementacc.js @@ -0,0 +1,86 @@ +const btc = config.liquid.btcasset; + +module.exports = async (user, transaction, limit, fee, assets, amount, address, memo, asset) => { + let total = amount; + + if (asset === btc) { + let covered = 0; + let nonbtc = assets.filter(a => a !== btc); + if (nonbtc.length === 1) { + let faucet = await db.Account.findOne({ + where: { + asset: nonbtc[0], + user_id: null + }, + lock: transaction.LOCK.UPDATE, + transaction + }); + + if (faucet) { + // TODO: is faucet ok with 0 fee in withdraw? + covered = faucet.balance; + if (covered > fee) covered = fee; + // covered = fee; + // if (covered > faucet.balance) covered = faucet.balance; + await faucet.decrement({balance: covered}, {transaction}); + await faucet.reload({transaction}); + await faucet.save({transaction}); + } + } + + total += fee - covered; + } + + if (limit && total > limit + fee) + throw new Error("Tx amount exceeds authorized amount"); + + if (asset !== btc || total) { + l.info("creating liquid payment", user.username, asset, total, fee); + + let account = await db.Account.findOne({ + where: { + user_id: user.id, + asset, + pubkey: null + }, + lock: transaction.LOCK.UPDATE, + order: [["balance", "DESC"]], + transaction + }); + + if (total > account.balance) { + l.warn("amount exceeds balance", { + total, + fee, + balance: account.balance + }); + throw new Error( + `Insufficient funds, need ${total} ${ + account.ticker === "BTC" ? "SAT" : account.ticker + }, have ${account.balance}` + ); + } + + await account.decrement({balance: total}, {transaction}); + await account.reload({transaction}); + + let payment = { + amount: -amount, + account_id: account.id, + fee, + memo, + user_id: user.id, + rate: app.get("rates")[user.currency], + currency: user.currency, + address, + confirmed: true, + received: false, + network: "liquid" + }; + + payment.account = account; + return payment; + } + + return null; +}; diff --git a/routes/liquid/withdraw.js b/routes/liquid/withdraw.js new file mode 100644 index 00000000..ec67091f --- /dev/null +++ b/routes/liquid/withdraw.js @@ -0,0 +1,35 @@ +const btc = config.liquid.btcasset; +const getFee = require('../../lib/feeliquidtx'); +const decrementAccount = require('./util/decrementacc'); + +module.exports = ah(async (req, res) => { + let {user} = req; + let {asset = btc, address, amount, memo} = req.body; + + let payment; + try { + await db.transaction(async transaction => { + payment = await decrementAccount(user, transaction, toSats(amount), 0, [asset], toSats(amount), address, memo, asset); + + const txid = (await lq.sendToAddress(address, amount, 'withdrawal', memo, true)); + const fee = await getFee(txid); + + if(payment) { + payment.fee = fee; + const { account } = payment; + + await db.Payment.create(payment, {transaction}); + + emit(user.username, "account", account.get({ plain: true })); + emit(user.username, "payment", payment); + } + + }); + + l.info("withdraw liquid", user.username, amount); + res.send(payment); + } catch (e) { + l.error("error withdrawing liquid", e.message); + return res.status(500).send(e.message); + } +}); diff --git a/routes/payments.js b/routes/payments.js index dc651b39..cb09de63 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -164,6 +164,7 @@ ah(async () => { app.get("/liquid/generate", auth, require("./liquid/generate")); app.post("/liquid/fee", auth, require("./liquid/fee")); app.post("/liquid/send", auth, require("./liquid/send")); + app.post("/liquid/withdraw", auth, require("./liquid/withdraw")); app.post("/taxi", auth, require("./liquid/taxi")); require("./liquid/receive"); |
