aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGyulai Zoltan <[email protected]>2021-09-28 16:51:35 +0300
committerGyulai Zoltan <[email protected]>2021-09-28 16:51:35 +0300
commit5f949a00ab98792db22bb5ab0104a06c714932f2 (patch)
treeea936c9499192758d521f8f61b0d85f8844cbafa
parented3482fc15d3d8f8e8b3bceff7d473fd29601280 (diff)
downloadcoinos-server-5f949a00ab98792db22bb5ab0104a06c714932f2.tar.gz
coinos-server-5f949a00ab98792db22bb5ab0104a06c714932f2.zip
feat: added liquid withdrawal
-rw-r--r--lib/feeliquidtx.js13
-rw-r--r--routes/liquid/send.js77
-rw-r--r--routes/liquid/util/decrementacc.js86
-rw-r--r--routes/liquid/withdraw.js35
-rw-r--r--routes/payments.js1
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");