From c3a28b2d1b1c902f7b691d5fefe70cda573d954f Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 31 May 2022 23:56:09 -0700 Subject: update readme config paths --- README.md | 4 ++-- doc/fund-server-bitcoin-cli.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1b3c832d..ad1a6724 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ docker network create net docker run -it -v $(pwd):/app --entrypoint yarn asoltys/coinos-server docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d docker exec -i mariadb mysql -u root -ppassword < db/schema.sql -docker exec -it liquid elements-cli -conf=/config/elements.conf sendtoaddress AzpsKhC6xE9FEK4aWAzMnbvueMLiSa5ym1xpuYogFkHzWgMHSt8B79aNNbFppQzCSQ2yZ9E4nL6RQJU7 1000000 +docker exec -it liquid elements-cli -conf=/home/elements/.elements/elements.conf sendtoaddress AzpsKhC6xE9FEK4aWAzMnbvueMLiSa5ym1xpuYogFkHzWgMHSt8B79aNNbFppQzCSQ2yZ9E4nL6RQJU7 1000000 ``` then run this and keep reference to the result for the forthcoming [Config changes] @@ -266,4 +266,4 @@ To purchase a commercial license or to inquire about customized, managed instanc [pwd file]:./sampleconfig/lnd/pwd [licensed]:./LICENSE.md [contact@coinos.io]:mailto:contact@coinos.io -[generate some BTC]:./doc/fund-server-bitcoin-cli.md \ No newline at end of file +[generate some BTC]:./doc/fund-server-bitcoin-cli.md diff --git a/doc/fund-server-bitcoin-cli.md b/doc/fund-server-bitcoin-cli.md index 093c537c..e0a2c5e3 100644 --- a/doc/fund-server-bitcoin-cli.md +++ b/doc/fund-server-bitcoin-cli.md @@ -14,7 +14,7 @@ bitcoin-cli -regtest -rpcuser=admin1 -rpcpassword=123 getnewaddress > bcrt1qzneawwyxe0fts5p8a6tsp4gu2mfnqzs92235hm # (example) # mine a block to the new address -bitcoin-cli -regtest -datadir=/config generatetoaddress 101 theaddressgeneratedabove +bitcoin-cli -regtest -datadir=/home/bitcoin/.bitcoin generatetoaddress 101 theaddressgeneratedabove # verify you got the reward by doing: bitcoin-cli -regtest -rpcuser=admin1 -rpcpassword=123 getbalance -- cgit v1.2.3 From 2549d087fd55191cd711e02522892092ba7e2fda Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 6 Jun 2022 08:48:26 -0500 Subject: Implemented liquid fees (?) --- routes/bitcoin/send.js | 1 - routes/liquid/send.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index cf7e89ef..aa3a7640 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -102,7 +102,6 @@ module.exports = ah(async (req, res) => { ); // record the external bitcoin transaction - // no need to record the withdrawal fee - since that is internal only let params = { amount: -amount, fee, diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 6f3616e8..1e4c62d2 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -84,6 +84,11 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { total += fee - covered; } + // get withdrawal fee + // 'total' refers to the total before the withdrawal fee + // (i.e. the total liquid bitcoin that leaves this server) + var withdrawalFee = amount * withdrawalFeeMultiplier; + if (limit && total > limit + fee) throw new Error("Tx amount exceeds authorized amount"); @@ -112,11 +117,54 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { account.ticker === "BTC" ? "SAT" : account.ticker }, have ${account.balance}` ); + } else if (total + withdrawalFee > account.balance) { + l.warn("amount plus withdrawal fee exceeds balance", { + total, + fee, + withdrawalFee, + balance: account.balance + }); + throw new Error( + `Insufficient funds, need ${total + withdrawalFee} ${ + account.ticker === "BTC" ? "SAT" : account.ticker + }, have ${account.balance}` + ); } - await account.decrement({ balance: total }, { transaction }); + await account.decrement({ balance: (total + withdrawalFee)}, { transaction }); await account.reload({ transaction }); + let receiverAccount = await db.Account.findOne({ + where: { + "$user.username$": withdrawalFeeReceiver + }, + include: [ + { + model: db.User, + as: "user" + }, + ], + lock: transaction.LOCK.UPDATE, + transaction + }); + + await receiverAccount.increment({ balance: withdrawalFee }, { transaction }); + await receiverAccount.reload({ transaction }); + let fee_payment = { + amount: withdrawalFee, + fee: 0, + memo: "Liquid withdrawal fee", + account_id: receiverAccount.id, + user_id: receiverAccount.user_id, + rate: app.get("rates")[receiverAccount.user.currency], + currency: receiverAccount.user.currency, + confirmed: true, + received: true, + network: "COINOS" + }; + fee_payment.account = receiverAccount; + payments.push(fee_payment); + let payment = { amount: -amount, account_id: account.id, @@ -128,7 +176,8 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { address, confirmed: true, received: false, - network: "liquid" + network: "liquid", + fee_payment_id: fee_payment.id }; payment.account = account; -- cgit v1.2.3 From 8fcd976a04d1cfffdf84306c39a4d6c526aa0a22 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 6 Jun 2022 14:51:48 -0500 Subject: Added withdrawal fee credits, which can pay withdrawal fees --- db/models/accounts.js | 9 +++++++++ routes/bitcoin/send.js | 46 ++++++++++++++++++++++++++++------------------ routes/liquid/send.js | 48 ++++++++++++++++++++++++++++++------------------ 3 files changed, 67 insertions(+), 36 deletions(-) diff --git a/db/models/accounts.js b/db/models/accounts.js index 12fef548..88ad2d44 100644 --- a/db/models/accounts.js +++ b/db/models/accounts.js @@ -124,6 +124,15 @@ const attributes = { comment: null, field: "balance" }, + fee_credits: { + type: DataTypes.DOUBLE, + allowNull: true, + defaultValue: 0.0, + primaryKey: false, + autoIncrement: false, + comment: "Credits that can be used towards paying withdrawal fees", + field: "fee_credits" + }, pending: { type: DataTypes.DOUBLE, allowNull: true, diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index aa3a7640..efcedb38 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -34,7 +34,7 @@ module.exports = ah(async (req, res) => { // get withdrawal fee // 'total' refers to the total before the withdrawal fee // (i.e. the total bitcoin that leaves this server) - let withdrawalFee = amount * withdrawalFeeMultiplier; + let withdrawalFee = Math.floor(amount * withdrawalFeeMultiplier); try { // withdraw bitcoin @@ -67,6 +67,14 @@ module.exports = ah(async (req, res) => { throw new Error("low balance (after withdrawal fee)"); } + // use user's credits to reduce fee, if available + console.log(account.fee_credits); + let withdrawalFeeDeduction = Math.min(account.fee_credits, withdrawalFee); + if (withdrawalFeeDeduction) { + await account.decrement({ fee_credits: withdrawalFeeDeduction }, { transaction }); + await account.reload({ transaction }); + } + await account.decrement({ balance: (total + withdrawalFee) }, { transaction }); await account.reload({ transaction }); @@ -84,22 +92,24 @@ module.exports = ah(async (req, res) => { transaction }); - await receiverAccount.increment({ balance: withdrawalFee }, { transaction }); - await receiverAccount.reload({ transaction }); - let fee_payment = await db.Payment.create({ - amount: withdrawalFee, - fee: 0, - memo: "Bitcoin withdrawal fee", - account_id: receiverAccount.id, - user_id: receiverAccount.user_id, - rate: app.get("rates")[receiverAccount.user.currency], - currency: receiverAccount.user.currency, - confirmed: true, - received: true, - network: "COINOS" - }, - { transaction } - ); + let fee_payment_id = null; + if (withdrawalFee) { + await receiverAccount.increment({ balance: withdrawalFee }, { transaction }); + await receiverAccount.reload({ transaction }); + let fee_payment = await db.Payment.create({ + amount: withdrawalFee, + fee: 0, + memo: "Bitcoin withdrawal fee", + account_id: receiverAccount.id, + user_id: receiverAccount.user_id, + rate: app.get("rates")[receiverAccount.user.currency], + currency: receiverAccount.user.currency, + confirmed: true, + received: true, + network: "COINOS" + }, { transaction }); + fee_payment_id = fee_payment.id; + } // record the external bitcoin transaction let params = { @@ -114,7 +124,7 @@ module.exports = ah(async (req, res) => { confirmed: true, received: false, network: "bitcoin", - fee_payment_id: fee_payment.id + fee_payment_id: fee_payment_id }; if (config.bitcoin.walletpass) diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 1e4c62d2..8e21e4d4 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -87,7 +87,7 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { // get withdrawal fee // 'total' refers to the total before the withdrawal fee // (i.e. the total liquid bitcoin that leaves this server) - var withdrawalFee = amount * withdrawalFeeMultiplier; + var withdrawalFee = Math.floor(amount * withdrawalFeeMultiplier); if (limit && total > limit + fee) throw new Error("Tx amount exceeds authorized amount"); @@ -131,6 +131,14 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { ); } + // use user's credits to reduce fee, if available + console.log(account.fee_credits); + let withdrawalFeeDeduction = Math.min(account.fee_credits, withdrawalFee); + if (withdrawalFeeDeduction) { + await account.decrement({ fee_credits: withdrawalFeeDeduction }, { transaction }); + await account.reload({ transaction }); + } + await account.decrement({ balance: (total + withdrawalFee)}, { transaction }); await account.reload({ transaction }); @@ -148,22 +156,26 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { transaction }); - await receiverAccount.increment({ balance: withdrawalFee }, { transaction }); - await receiverAccount.reload({ transaction }); - let fee_payment = { - amount: withdrawalFee, - fee: 0, - memo: "Liquid withdrawal fee", - account_id: receiverAccount.id, - user_id: receiverAccount.user_id, - rate: app.get("rates")[receiverAccount.user.currency], - currency: receiverAccount.user.currency, - confirmed: true, - received: true, - network: "COINOS" - }; - fee_payment.account = receiverAccount; - payments.push(fee_payment); + let fee_payment_id = null; + if (withdrawalFee) { + await receiverAccount.increment({ balance: withdrawalFee }, { transaction }); + await receiverAccount.reload({ transaction }); + let fee_payment = { + amount: withdrawalFee, + fee: 0, + memo: "Liquid withdrawal fee", + account_id: receiverAccount.id, + user_id: receiverAccount.user_id, + rate: app.get("rates")[receiverAccount.user.currency], + currency: receiverAccount.user.currency, + confirmed: true, + received: true, + network: "COINOS" + }; + fee_payment.account = receiverAccount; + payments.push(fee_payment); + fee_payment_id = fee_payment.id; + } let payment = { amount: -amount, @@ -177,7 +189,7 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { confirmed: true, received: false, network: "liquid", - fee_payment_id: fee_payment.id + fee_payment_id: fee_payment_id }; payment.account = account; -- cgit v1.2.3 From 52716276db81bf8b9559cc2b361927d7be836897 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 7 Jun 2022 16:56:24 -0500 Subject: Withdrawal credits can be used to reduce the withdrawal fee --- routes/bitcoin/send.js | 2 +- routes/liquid/send.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index efcedb38..a9c95b31 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -68,11 +68,11 @@ module.exports = ah(async (req, res) => { } // use user's credits to reduce fee, if available - console.log(account.fee_credits); let withdrawalFeeDeduction = Math.min(account.fee_credits, withdrawalFee); if (withdrawalFeeDeduction) { await account.decrement({ fee_credits: withdrawalFeeDeduction }, { transaction }); await account.reload({ transaction }); + withdrawalFee -= withdrawalFeeDeduction; } await account.decrement({ balance: (total + withdrawalFee) }, { transaction }); diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 8e21e4d4..fcb05942 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -137,6 +137,7 @@ sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { if (withdrawalFeeDeduction) { await account.decrement({ fee_credits: withdrawalFeeDeduction }, { transaction }); await account.reload({ transaction }); + withdrawalFee -= withdrawalFeeDeduction; } await account.decrement({ balance: (total + withdrawalFee)}, { transaction }); -- cgit v1.2.3 From 2498ed9a93405c999c9336e0cb18a187716c1d03 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 13 Jun 2022 09:40:07 -0500 Subject: Withdrawal fee credits will be given for receiving Bitcoin/Liquid --- routes/bitcoin/receive.js | 4 ++++ routes/liquid/receive.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js index 5d8e21e7..5025a809 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -21,6 +21,9 @@ const network = const queue = {}; const seen = []; +// used to calculate how many credits to give +const withdrawalFeeMultiplier = 0.01; + zmqRawTx.on("message", async (topic, message, sequence) => { const hex = message.toString("hex"); let tx = bitcoin.Transaction.fromHex(message); @@ -192,6 +195,7 @@ setInterval(async () => { { pending: Math.min(account.pending, total) }, { transaction } ); + await account.increment({ fee_credits: total * withdrawalFeeMultiplier }, { transaction }); await account.reload({ transaction }); await p.save({ transaction }); diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index 0ee3e0c6..6d4c128b 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -13,6 +13,9 @@ const network = config.liquid.network === "mainnet" ? "liquid" : config.liquid.network ]; +// used to calculate how many credits to give +const withdrawalFeeMultiplier = 0.01; + const getAccount = async (params, transaction) => { let account = await db.Account.findOne({ where: params, @@ -340,6 +343,7 @@ setInterval(async () => { { pending: Math.min(p.account.pending, total) }, { transaction } ); + await account.increment({ fee_credits: total * withdrawalFeeMultiplier }, { transaction }); await p.account.reload({ transaction }); await p.save({ transaction }); -- cgit v1.2.3 From 1c02aa63933a234faa45eecbfdc82dae7f6e174c Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Mon, 13 Jun 2022 09:50:50 -0500 Subject: Ensure a whole number of fee credits is given in transactions --- routes/bitcoin/receive.js | 2 +- routes/liquid/receive.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/routes/bitcoin/receive.js b/routes/bitcoin/receive.js index 5025a809..5bdbcb72 100644 --- a/routes/bitcoin/receive.js +++ b/routes/bitcoin/receive.js @@ -195,7 +195,7 @@ setInterval(async () => { { pending: Math.min(account.pending, total) }, { transaction } ); - await account.increment({ fee_credits: total * withdrawalFeeMultiplier }, { transaction }); + await account.increment({ fee_credits: Math.floor(total * withdrawalFeeMultiplier) }, { transaction }); await account.reload({ transaction }); await p.save({ transaction }); diff --git a/routes/liquid/receive.js b/routes/liquid/receive.js index 6d4c128b..88166c91 100644 --- a/routes/liquid/receive.js +++ b/routes/liquid/receive.js @@ -343,7 +343,7 @@ setInterval(async () => { { pending: Math.min(p.account.pending, total) }, { transaction } ); - await account.increment({ fee_credits: total * withdrawalFeeMultiplier }, { transaction }); + await account.increment({ fee_credits: Math.floor(total * withdrawalFeeMultiplier) }, { transaction }); await p.account.reload({ transaction }); await p.save({ transaction }); -- cgit v1.2.3