From 66782a32054b98ffef1f5129d719acd8de1abbe2 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 31 May 2022 11:47:05 -0500 Subject: Initial BTC withdrawal fee test --- routes/bitcoin/send.js | 44 ++++++++++++++++++++++++++++++++++++++++---- routes/liquid/send.js | 2 ++ 2 files changed, 42 insertions(+), 4 deletions(-) (limited to 'routes') diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index 9d64bb59..526a89d0 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -1,4 +1,6 @@ const btc = config.liquid.btcasset; +const withdrawalFeeMultiplier = 0.01; // 1% withdrawal fee +const withdrawalFeeReceiver = "coinosfees"; // account that receives the fees module.exports = ah(async (req, res) => { let { user } = req; @@ -17,20 +19,31 @@ module.exports = ah(async (req, res) => { let total = 0; let change = 0; + console.log("tx.vout is "); + console.log(tx.vout); + for (let i = 0; i < tx.vout.length; i++) { let o = tx.vout[i]; total += toSats(o.value); - if (await isChange(o.scriptPubKey)) { - change += toSats(o.value); - } + console.log(o.scriptPubKey.addresses[0]); + + // if (await isChange("bcrt1q3y0af2vezj4w66zw397hmrglf4pk38pet3wr8g")) { + // change += toSats(o.value); + // } } total = total - change + fee; let amount = total - fee; + // 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 account, params; try { + // withdraw bitcoin await db.transaction(async transaction => { account = await db.Account.findOne({ where: { @@ -52,15 +65,37 @@ module.exports = ah(async (req, res) => { }); } + console.log("Account balance is " + account.balance); + console.log("Total is " + total); + if (total > account.balance) { l.error("amount exceeds balance", amount, fee, account.balance); throw new Error("low balance"); + } else if (total + withdrawalFee > account.balance) { + l.error("total (after withdrawal fee) exceeds balance", amount, fee, account.balance); + throw new Error("low balance (after withdrawal fee)"); } - await account.decrement({ balance: total }, { transaction }); + await account.decrement({ balance: (total + withdrawalFee) }, { transaction }); + await account.reload({ transaction }); + }); + + // pay withdrawal fee to receiver + await db.transaction(async transaction => { + let receiverAccount = await db.Account.findOne({ + where: { + username: withdrawalFeeReceiver + }, + lock: transaction.LOCK.UPDATE, + transaction + }); + + await account.increment({ balance: withdrawalFee }, { transaction }); await account.reload({ transaction }); }); + // record the external bitcoin transaction + // no need to record the withdrawal fee - since that is internal only params = { amount: -amount, fee, @@ -94,6 +129,7 @@ module.exports = ah(async (req, res) => { } catch (e) { if (e.message.includes("Insufficient")) e.message = "The coinos server hot wallet has insufficient funds to complete the payment, try again later"; l.error("error sending bitcoin", e.message); + console.log(e); return res.status(500).send(e.message); } }); diff --git a/routes/liquid/send.js b/routes/liquid/send.js index 59334103..6f3616e8 100644 --- a/routes/liquid/send.js +++ b/routes/liquid/send.js @@ -1,6 +1,8 @@ const btc = config.liquid.btcasset; const lcad = config.liquid.cadasset; const { Transaction } = require("liquidjs-lib"); +const withdrawalFeeMultiplier = 0.01; // 1% withdrawal fee +const withdrawalFeeReceiver = "coinosfees"; // 1% withdrawal fee sendLiquid = async ({ asset, amount, user, address, memo, tx, limit }) => { try { -- cgit v1.2.3 From bfe6091feeabdb9562250cf0544863bc4f035c09 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 31 May 2022 11:51:23 -0500 Subject: Revert code commenting --- routes/bitcoin/send.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'routes') diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index 526a89d0..326518a0 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -26,11 +26,9 @@ module.exports = ah(async (req, res) => { let o = tx.vout[i]; total += toSats(o.value); - console.log(o.scriptPubKey.addresses[0]); - - // if (await isChange("bcrt1q3y0af2vezj4w66zw397hmrglf4pk38pet3wr8g")) { - // change += toSats(o.value); - // } + if (await isChange(o.scriptPubKey)) { + change += toSats(o.value); + } } total = total - change + fee; -- cgit v1.2.3 From 2200e185f7099defdad3e510e7f74c84017d833b Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 31 May 2022 10:22:17 -0700 Subject: create payment record for withdrawal fee --- routes/bitcoin/send.js | 30 +++++++++++++++++++++--------- routes/users.js | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'routes') diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index 326518a0..51962367 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -19,9 +19,6 @@ module.exports = ah(async (req, res) => { let total = 0; let change = 0; - console.log("tx.vout is "); - console.log(tx.vout); - for (let i = 0; i < tx.vout.length; i++) { let o = tx.vout[i]; total += toSats(o.value); @@ -63,9 +60,6 @@ module.exports = ah(async (req, res) => { }); } - console.log("Account balance is " + account.balance); - console.log("Total is " + total); - if (total > account.balance) { l.error("amount exceeds balance", amount, fee, account.balance); throw new Error("low balance"); @@ -82,14 +76,32 @@ module.exports = ah(async (req, res) => { await db.transaction(async transaction => { let receiverAccount = await db.Account.findOne({ where: { - username: withdrawalFeeReceiver + "$user.username$": withdrawalFeeReceiver }, + include: [ + { + model: db.User, + as: "user" + }, + ], lock: transaction.LOCK.UPDATE, transaction }); - await account.increment({ balance: withdrawalFee }, { transaction }); - await account.reload({ transaction }); + await receiverAccount.increment({ balance: withdrawalFee }, { transaction }); + await receiverAccount.reload({ transaction }); + 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" + }); }); // record the external bitcoin transaction diff --git a/routes/users.js b/routes/users.js index 549de828..6bf9a063 100644 --- a/routes/users.js +++ b/routes/users.js @@ -365,7 +365,7 @@ app.post( ); app.post( - "/taboggan", + "/doggin", ah(async (req, res) => { try { const { params, sig, key } = req.body; -- cgit v1.2.3 From 72e945305349cf18d45e74e9537e9adbd655c68c Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 31 May 2022 10:34:51 -0700 Subject: do fee decrement as part of single db transaction --- routes/bitcoin/send.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'routes') diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index 51962367..67857121 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -70,10 +70,7 @@ module.exports = ah(async (req, res) => { await account.decrement({ balance: (total + withdrawalFee) }, { transaction }); await account.reload({ transaction }); - }); - // pay withdrawal fee to receiver - await db.transaction(async transaction => { let receiverAccount = await db.Account.findOne({ where: { "$user.username$": withdrawalFeeReceiver @@ -101,7 +98,9 @@ module.exports = ah(async (req, res) => { confirmed: true, received: true, network: "COINOS" - }); + }, + { transaction } + ); }); // record the external bitcoin transaction -- cgit v1.2.3 From 1db7a0b0a2e897b67617a67fc852f538baecce76 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 31 May 2022 14:14:06 -0500 Subject: Add fee payment to database --- db/index.js | 5 ++++ db/models/payments.js | 9 +++++++ routes/bitcoin/send.js | 72 +++++++++++++++++++++++++------------------------- 3 files changed, 50 insertions(+), 36 deletions(-) (limited to 'routes') diff --git a/db/index.js b/db/index.js index 57586954..5a10a01a 100644 --- a/db/index.js +++ b/db/index.js @@ -162,4 +162,9 @@ Referral.belongsTo(User, { foreignKey: "user_id", }); +Payment.belongsTo(Payment, { + as: "fee", + foreignKey: "fee_payment_id" +}); + db.Order = Order; diff --git a/db/models/payments.js b/db/models/payments.js index c315a5a0..bbf7c436 100644 --- a/db/models/payments.js +++ b/db/models/payments.js @@ -189,6 +189,15 @@ const attributes = { autoIncrement: false, comment: null, field: "confirmed" + }, + fee_payment_id: { + type: DataTypes.INTEGER(11), + allowNull: true, + defaultValue: null, + primaryKey: false, + autoIncrement: false, + comment: null, + field: "fee_payment_id" } }; diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index 67857121..70cca161 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -36,11 +36,10 @@ module.exports = ah(async (req, res) => { // (i.e. the total bitcoin that leaves this server) let withdrawalFee = amount * withdrawalFeeMultiplier; - let account, params; try { // withdraw bitcoin await db.transaction(async transaction => { - account = await db.Account.findOne({ + let account = await db.Account.findOne({ where: { id: user.account_id }, @@ -87,7 +86,7 @@ module.exports = ah(async (req, res) => { await receiverAccount.increment({ balance: withdrawalFee }, { transaction }); await receiverAccount.reload({ transaction }); - await db.Payment.create({ + let fee_payment = await db.Payment.create({ amount: withdrawalFee, fee: 0, memo: "Bitcoin withdrawal fee", @@ -101,40 +100,41 @@ module.exports = ah(async (req, res) => { }, { transaction } ); - }); - // record the external bitcoin transaction - // no need to record the withdrawal fee - since that is internal only - params = { - amount: -amount, - fee, - memo, - account_id: account.id, - user_id: user.id, - rate: app.get("rates")[user.currency], - currency: user.currency, - address, - confirmed: true, - received: false, - network: "bitcoin" - }; - - if (config.bitcoin.walletpass) - await bc.walletPassphrase(config.bitcoin.walletpass, 300); - - hex = (await bc.signRawTransactionWithWallet(hex)).hex; - params.hash = await bc.sendRawTransaction(hex); - - let payment = await db.Payment.create(params); - - payment = payment.get({ plain: true }); - payment.account = account.get({ plain: true }); - - emit(user.username, "payment", payment); - res.send(payment); - - payments.push(params.hash); - l.info("sent bitcoin", user.username, total); + // record the external bitcoin transaction + // no need to record the withdrawal fee - since that is internal only + let params = { + amount: -amount, + fee, + memo, + account_id: account.id, + user_id: user.id, + rate: app.get("rates")[user.currency], + currency: user.currency, + address, + confirmed: true, + received: false, + network: "bitcoin", + fee_payment_id: fee_payment.id + }; + + if (config.bitcoin.walletpass) + await bc.walletPassphrase(config.bitcoin.walletpass, 300); + + hex = (await bc.signRawTransactionWithWallet(hex)).hex; + params.hash = await bc.sendRawTransaction(hex); + + let payment = await db.Payment.create(params); + + payment = payment.get({ plain: true }); + payment.account = account.get({ plain: true }); + + emit(user.username, "payment", payment); + res.send(payment); + + payments.push(params.hash); + l.info("sent bitcoin", user.username, total); + }); } catch (e) { if (e.message.includes("Insufficient")) e.message = "The coinos server hot wallet has insufficient funds to complete the payment, try again later"; l.error("error sending bitcoin", e.message); -- cgit v1.2.3 From 344c60aa9d970e8f6a5955dc11393c962b8bd0b0 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 31 May 2022 12:19:36 -0700 Subject: use transaction for payment creation --- db/index.js | 2 +- routes/bitcoin/send.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'routes') diff --git a/db/index.js b/db/index.js index 5a10a01a..c4dab977 100644 --- a/db/index.js +++ b/db/index.js @@ -163,7 +163,7 @@ Referral.belongsTo(User, { }); Payment.belongsTo(Payment, { - as: "fee", + as: "fee_payment", foreignKey: "fee_payment_id" }); diff --git a/routes/bitcoin/send.js b/routes/bitcoin/send.js index 70cca161..cf7e89ef 100644 --- a/routes/bitcoin/send.js +++ b/routes/bitcoin/send.js @@ -124,7 +124,7 @@ module.exports = ah(async (req, res) => { hex = (await bc.signRawTransactionWithWallet(hex)).hex; params.hash = await bc.sendRawTransaction(hex); - let payment = await db.Payment.create(params); + let payment = await db.Payment.create(params, { transaction }); payment = payment.get({ plain: true }); payment.account = account.get({ plain: true }); -- cgit v1.2.3