From e4adaf7ed7cf038898ebd18bf332e09ba355bf27 Mon Sep 17 00:00:00 2001 From: sairajzero Date: Sat, 5 Nov 2022 03:56:40 +0530 Subject: [PATCH] Minor changes and Bug fixes - deduce BTC fee from users - If timeout rejected tx are confirmed, refund the asset - Blockchain bond and Bob's fund withdraw now sends equivalent BTC to users (via BTC blockchain) - Fixed minor bugs - Changed toFixed (fn to limit the decimal) to toStandardDecimal (set_global.js) --- args/schema.sql | 2 + docs/scripts/btcOperator.js | 67 +++++++++++++++--------- src/background.js | 100 +++++++++++++++++++++++++++--------- src/blockchain.js | 28 +++++----- src/coupling.js | 2 +- src/market.js | 6 +-- src/price.js | 10 ++-- src/services/bobs-fund.js | 2 +- src/services/conversion.js | 2 +- src/set_globals.js | 2 + 10 files changed, 146 insertions(+), 75 deletions(-) diff --git a/args/schema.sql b/args/schema.sql index 8bc523f..0b7fcf4 100644 --- a/args/schema.sql +++ b/args/schema.sql @@ -288,6 +288,8 @@ CREATE TABLE DirectConvert( CREATE TABLE RefundTransact( id INT NOT NULL AUTO_INCREMENT, floID CHAR(34) NOT NULL, + asset_type TINYINT NOT NULL, + asset VARCHAR(32) NOT NULL, amount DECIMAL(16, 8), in_txid VARCHAR(128), out_txid VARCHAR(128), diff --git a/docs/scripts/btcOperator.js b/docs/scripts/btcOperator.js index bb0b7ca..baa70a5 100644 --- a/docs/scripts/btcOperator.js +++ b/docs/scripts/btcOperator.js @@ -1,4 +1,4 @@ -(function (EXPORTS) { //btcOperator v1.0.12 +(function (EXPORTS) { //btcOperator v1.0.13 /* BTC Crypto and API Operator */ const btcOperator = EXPORTS; @@ -307,8 +307,8 @@ parameters.receivers.forEach(id => !validateAddress(id) ? invalids.push(id) : null); if (invalids.length) throw "Invalid receivers:" + invalids; - if (parameters.change_addr && !validateAddress(parameters.change_addr)) - throw "Invalid change_address:" + parameters.change_addr; + if (parameters.change_address && !validateAddress(parameters.change_address)) + throw "Invalid change_address:" + parameters.change_address; //fee and amounts if ((typeof parameters.fee !== "number" || parameters.fee <= 0) && parameters.fee !== null) //fee = null (auto calc) throw "Invalid fee:" + parameters.fee; @@ -323,16 +323,29 @@ return parameters; } - function createTransaction(senders, redeemScripts, receivers, amounts, fee, change_addr) { + function createTransaction(senders, redeemScripts, receivers, amounts, fee, change_address, fee_from_receiver) { return new Promise((resolve, reject) => { let total_amount = parseFloat(amounts.reduce((t, a) => t + a, 0).toFixed(8)); const tx = coinjs.transaction(); - let output_size = addOutputs(tx, receivers, amounts, change_addr); + let output_size = addOutputs(tx, receivers, amounts, change_address); addInputs(tx, senders, redeemScripts, total_amount, fee, output_size).then(result => { - if (result.change_amount > 0) + if (result.change_amount > 0) //add change amount if any tx.outs[tx.outs.length - 1].value = parseInt(result.change_amount * SATOSHI_IN_BTC); //values are in satoshi - else - tx.outs.pop(); //remove the change output if no change_amount + if (fee_from_receiver) { //deduce fee from receivers if fee_from_receiver + let fee_remaining = parseInt(result.fee * SATOSHI_IN_BTC); + for (let i = 0; i < tx.outs.length - 1 && fee_remaining > 0; i++) { + if (fee_remaining < tx.outs[i].value) { + tx.outs[i].value -= fee_remaining; + fee_remaining = 0; + } else { + fee_remaining -= tx.outs[i].value; + tx.outs[i].value = 0; + } + } + if (fee_remaining > 0) + return reject("Send amount is less than fee"); + } + tx.outs = tx.outs.filter(o => o.value !== 0); //remove all output with value 0 result.output_size = output_size; result.output_amount = total_amount; result.total_size = BASE_TX_SIZE + output_size + result.input_size; @@ -342,10 +355,10 @@ }) } - function addInputs(tx, senders, redeemScripts, total_amount, fee, output_size) { + function addInputs(tx, senders, redeemScripts, total_amount, fee, output_size, fee_from_receiver) { return new Promise((resolve, reject) => { if (fee !== null) { - addUTXOs(tx, senders, redeemScripts, total_amount + fee, false).then(result => { + addUTXOs(tx, senders, redeemScripts, fee_from_receiver ? total_amount : total_amount + fee, false).then(result => { result.fee = fee; resolve(result); }).catch(error => reject(error)) @@ -353,7 +366,10 @@ get_fee_rate().then(fee_rate => { let net_fee = BASE_TX_SIZE * fee_rate; net_fee += (output_size * fee_rate); - addUTXOs(tx, senders, redeemScripts, total_amount + net_fee, fee_rate).then(result => { + (fee_from_receiver ? + addUTXOs(tx, senders, redeemScripts, total_amount, false) : + addUTXOs(tx, senders, redeemScripts, total_amount + net_fee, fee_rate) + ).then(result => { result.fee = parseFloat((net_fee + (result.input_size * fee_rate)).toFixed(8)); result.fee_rate = fee_rate; resolve(result); @@ -416,14 +432,14 @@ }) } - function addOutputs(tx, receivers, amounts, change_addr) { + function addOutputs(tx, receivers, amounts, change_address) { let size = 0; for (let i in receivers) { tx.addoutput(receivers[i], amounts[i]); size += _sizePerOutput(receivers[i]); } - tx.addoutput(change_addr, 0); - size += _sizePerOutput(change_addr); + tx.addoutput(change_address, 0); + size += _sizePerOutput(change_address); return size; } @@ -464,9 +480,9 @@ } */ - btcOperator.sendTx = function (senders, privkeys, receivers, amounts, fee, change_addr = null) { + btcOperator.sendTx = function (senders, privkeys, receivers, amounts, fee = null, options = {}) { return new Promise((resolve, reject) => { - createSignedTx(senders, privkeys, receivers, amounts, fee, change_addr).then(result => { + createSignedTx(senders, privkeys, receivers, amounts, fee, options).then(result => { debugger; broadcastTx(result.transaction.serialize()) .then(txid => resolve(txid)) @@ -475,7 +491,7 @@ }) } - const createSignedTx = btcOperator.createSignedTx = function (senders, privkeys, receivers, amounts, fee = null, change_addr = null) { + const createSignedTx = btcOperator.createSignedTx = function (senders, privkeys, receivers, amounts, fee = null, options = {}) { return new Promise((resolve, reject) => { try { ({ @@ -489,7 +505,7 @@ receivers, amounts, fee, - change_addr + change_address: options.change_address })); } catch (e) { return reject(e) @@ -504,7 +520,7 @@ if (redeemScripts.includes(null)) //TODO: segwit return reject("Unable to get redeem-script"); //create transaction - createTransaction(senders, redeemScripts, receivers, amounts, fee, change_addr || senders[0]).then(result => { + createTransaction(senders, redeemScripts, receivers, amounts, fee, options.change_address || senders[0], options.fee_from_receiver).then(result => { let tx = result.transaction; console.debug("Unsigned:", tx.serialize()); new Set(wif_keys).forEach(key => console.debug("Signing key:", key, tx.sign(key, 1 /*sighashtype*/))); //Sign the tx using private key WIF @@ -514,7 +530,7 @@ }) } - btcOperator.createTx = function (senders, receivers, amounts, fee = null, change_addr = null) { + btcOperator.createTx = function (senders, receivers, amounts, fee = null, options = {}) { return new Promise((resolve, reject) => { try { ({ @@ -526,7 +542,7 @@ receivers, amounts, fee, - change_addr + change_address: options.change_address })); } catch (e) { return reject(e) @@ -535,7 +551,7 @@ if (redeemScripts.includes(null)) //TODO: segwit return reject("Unable to get redeem-script"); //create transaction - createTransaction(senders, redeemScripts, receivers, amounts, fee, change_addr || senders[0]).then(result => { + createTransaction(senders, redeemScripts, receivers, amounts, fee, options.change_address || senders[0], options.fee_from_receiver).then(result => { result.tx_hex = result.transaction.serialize(); delete result.transaction; resolve(result); @@ -543,7 +559,7 @@ }) } - btcOperator.createMultiSigTx = function (sender, redeemScript, receivers, amounts, fee = null) { + btcOperator.createMultiSigTx = function (sender, redeemScript, receivers, amounts, fee = null, options = {}) { return new Promise((resolve, reject) => { //validate tx parameters if (validateAddress(sender) !== "multisig") @@ -561,13 +577,14 @@ } = validateTxParameters({ receivers, amounts, - fee + fee, + change_address: options.change_address })); } catch (e) { return reject(e) } //create transaction - createTransaction([sender], [redeemScript], receivers, amounts, fee, sender).then(result => { + createTransaction([sender], [redeemScript], receivers, amounts, fee, options.change_address || sender, options.fee_from_receiver).then(result => { result.tx_hex = result.transaction.serialize(); delete result.transaction; resolve(result); diff --git a/src/background.js b/src/background.js index 8aad551..a5acb23 100644 --- a/src/background.js +++ b/src/background.js @@ -152,7 +152,7 @@ function retryVaultWithdrawal() { } else if (r.asset_type == pCode.ASSET_TYPE_TOKEN) blockchain.withdrawAsset.retry(r.floID, r.asset, r.amount, r.id) }) - }).catch(error => reject(error)) + }).catch(error => console.error(error)) } function confirmVaultWithdraw() { @@ -210,7 +210,16 @@ verifyTx.BTC = function (sender, txid) { } function verifyConvert() { - DB.query("UPDATE DirectConvert SET r_status=? WHERE r_status=? AND locktime { + //Set all timeout convert request to refund mode (thus, asset will be refund if tx gets confirmed later) + let req_timeout = new Date(Date.now() - REQUEST_TIMEOUT), + to_refund_sql = "INSERT INTO RefundTransact (floID, in_txid, asset_type, asset, r_status)" + + " SELECT floID, in_txid, ? AS asset_type, ? AS asset, r_status" + + " WHERE r_status=? AND locktime { DB.query("SELECT id, floID, mode, in_txid, amount, quantity FROM DirectConvert WHERE r_status=? AND coin=?", [pCode.STATUS_PENDING, "BTC"]).then(results => { results.forEach(r => { if (r.mode == pCode.CONVERT_MODE_GET) { @@ -242,7 +251,7 @@ function verifyConvert() { } }) }).catch(error => console.error(error)) - }).catch(error => reject(error)) + }).catch(error => console.error(error)) } function retryConvert() { @@ -345,11 +354,34 @@ function confirmConvertFundWithdraw() { } function verifyRefund() { - DB.query("SELECT id, floID, in_txid FROM RefundTransact WHERE r_status=?", [pCode.STATUS_PENDING]).then(results => { + DB.query("SELECT id, floID, asset_type, asset, in_txid FROM RefundTransact WHERE r_status=?", [pCode.STATUS_PENDING]).then(results => { results.forEach(r => { - verifyTx.token(r.floID, r.in_txid, true) - .then(({ amount }) => blockchain.refundTransact.init(r.floID, amount, r.id)) - .catch(error => { + if (r.ASSET_TYPE_COIN) { + if (r.asset == "FLO") + verifyTx.FLO(r.floID, r.in_txid) + .then(amount => blockchain.refundTransact.init(r.floID, r.asset, amount, r.id)) + .catch(error => { + console.error(error); + if (error[0]) + DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_REJECTED, r.id]) + .then(_ => null).catch(error => console.error(error)); + }); + else if (r.asset == "BTC") + verifyTx.BTC(r.floID, r.in_txid) + .then(amount => blockchain.refundTransact.init(r.floID, r.asset, amount, r.id)) + .catch(error => { + console.error(error); + if (error[0]) + DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_REJECTED, r.id]) + .then(_ => null).catch(error => console.error(error)); + }); + } else if (r.ASSET_TYPE_TOKEN) + verifyTx.token(r.floID, r.in_txid).then(({ token, amount }) => { + if (token !== r.asset) + throw ([true, "Transaction token mismatched"]); + else + blockchain.refundTransact.init(r.floID, token, amount, r.id); + }).catch(error => { console.error(error); if (error[0]) DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_REJECTED, r.id]) @@ -360,36 +392,54 @@ function verifyRefund() { } function retryRefund() { - DB.query("SELECT id, floID, amount FROM RefundTransact WHERE r_status=?", [pCode.STATUS_PROCESSING]).then(results => { - results.forEach(r => blockchain.refundTransact.retry(r.floID, r.amount, r.id)) + DB.query("SELECT id, floID, asset, amount FROM RefundTransact WHERE r_status=?", [pCode.STATUS_PROCESSING]).then(results => { + results.forEach(r => blockchain.refundTransact.retry(r.floID, r.asset, r.amount, r.id)) }).catch(error => console.error(error)) } function confirmRefund() { DB.query("SELECT * FROM RefundTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => { - results.forEach(r => { - floTokenAPI.getTx(r.out_txid).then(tx => { - if (!tx.transactionDetails.blockheight || !tx.transactionDetails.confirmations) //Still not confirmed - return; - DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_SUCCESS, r.id]) - .then(result => console.info(`Refunded ${r.amount} to ${r.floID}`)) - .catch(error => console.error(error)); - }).catch(error => console.error(error)); + results.forEach(r => { //TODO + if (r.ASSET_TYPE_COIN) { + if (r.asset == "FLO") + floBlockchainAPI.getTx(r.out_txid).then(tx => { + if (!tx.blockheight || !tx.confirmations) //Still not confirmed + return; + DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_SUCCESS, r.id]) + .then(result => console.info(`Refunded ${r.amount} ${r.asset} to ${r.floID}`)) + .catch(error => console.error(error)) + }).catch(error => console.error(error)); + else if (r.asset == "BTC") + btcOperator.getTx(r.out_txid).then(tx => { + if (!tx.blockhash || !tx.confirmations) //Still not confirmed + return; + DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_SUCCESS, r.id]) + .then(result => console.info(`Refunded ${r.amount} ${r.asset} to ${r.floID}`)) + .catch(error => console.error(error)) + }).catch(error => console.error(error)); + } else if (r.ASSET_TYPE_TOKEN) + floTokenAPI.getTx(r.out_txid).then(tx => { + if (!tx.transactionDetails.blockheight || !tx.transactionDetails.confirmations) //Still not confirmed + return; + DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_SUCCESS, r.id]) + .then(result => console.info(`Refunded ${r.amount} ${r.asset} to ${r.floID}`)) + .catch(error => console.error(error)); + }).catch(error => console.error(error)); }) }).catch(error => console.error(error)) } function retryBondClosing() { - DB.query("SELECT id, floID, amount FROM CloseBondTransact WHERE r_status=?", [pCode.STATUS_PENDING]).then(results => { - results.forEach(r => blockchain.bondTransact.retry(r.floID, r.amount, r.id)) + DB.query("SELECT id, floID, amount, btc_net, usd_net FROM CloseBondTransact WHERE r_status=?", [pCode.STATUS_PENDING]).then(results => { + results.forEach(r => blockchain.bondTransact.retry(r.floID, r.amount, r.btc_net, r.usd_net, r.id)) }).catch(error => console.error(error)) } function confirmBondClosing() { DB.query("SELECT * FROM CloseBondTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => { results.forEach(r => { - floTokenAPI.getTx(r.txid).then(tx => { - if (!tx.transactionDetails.blockheight || !tx.transactionDetails.confirmations) //Still not confirmed + btcOperator.getTx(r.txid).then(tx => { + if (!tx.blockhash || !tx.confirmations) //Still not confirmed return; let closeBondString = bond_util.stringify.end(r.bond_id, r.end_date, r.btc_net, r.usd_net, r.amount, r.ref_sign, r.txid); floBlockchainAPI.writeData(global.myFloID, closeBondString, global.myPrivKey, bond_util.config.adminID).then(txid => { @@ -403,16 +453,16 @@ function confirmBondClosing() { } function retryFundClosing() { - DB.query("SELECT id, floID, amount FROM CloseFundTransact WHERE r_status=?", [pCode.STATUS_PENDING]).then(results => { - results.forEach(r => blockchain.fundTransact.retry(r.floID, r.amount, r.id)) + DB.query("SELECT id, floID, amount, btc_net, usd_net FROM CloseFundTransact WHERE r_status=?", [pCode.STATUS_PENDING]).then(results => { + results.forEach(r => blockchain.fundTransact.retry(r.floID, r.amount, r.btc_net, r.usd_net, r.id)) }).catch(error => console.error(error)) } function confirmFundClosing() { DB.query("SELECT * FROM CloseFundTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => { results.forEach(r => { - floTokenAPI.getTx(r.txid).then(tx => { - if (!tx.transactionDetails.blockheight || !tx.transactionDetails.confirmations) //Still not confirmed + btcOperator.getTx(r.txid).then(tx => { + if (!tx.blockhash || !tx.confirmations) //Still not confirmed return; let closeFundString = fund_util.stringify.end(r.fund_id, r.floID, r.end_date, r.btc_net, r.usd_net, r.amount, r.ref_sign, r.txid); floBlockchainAPI.writeData(global.myFloID, closeFundString, global.myPrivKey, fund_util.config.adminID).then(txid => { diff --git a/src/blockchain.js b/src/blockchain.js index 60f9e42..13aec35 100644 --- a/src/blockchain.js +++ b/src/blockchain.js @@ -79,7 +79,7 @@ function sendTx(floID, asset, quantity, sinkID, sinkKey, message) { case "BTC": let btc_sinkID = btcOperator.convert.legacy2bech(sinkID), btc_receiver = btcOperator.convert.legacy2bech(floID); - return btcOperator.sendTx(btc_sinkID, sinkKey, btc_receiver, quantity, null); + return btcOperator.sendTx(btc_sinkID, sinkKey, btc_receiver, quantity, null, { fee_from_receiver: true }); default: return floTokenAPI.sendToken(sinkKey, quantity, floID, message, asset); } @@ -95,6 +95,7 @@ const updateSyntax = { }; function sendAsset(floID, asset, quantity, type, id) { + quantity = global.toStandardDecimal(quantity); getSinkID(quantity, asset).then(sinkID => { let callback = (sinkKey) => { //Send asset to user via API @@ -118,7 +119,7 @@ function sendAsset(floID, asset, quantity, type, id) { } function withdrawAsset_init(floID, asset, amount) { - amount = parseFloat(amount.toFixed(8)); + amount = global.toStandardDecimal(amount); let asset_type = ["FLO", "BTC"].includes(asset) ? pCode.ASSET_TYPE_COIN : pCode.ASSET_TYPE_TOKEN; DB.query("INSERT INTO VaultTransactions (floID, mode, asset_type, asset, amount, r_status) VALUES (?)", [[floID, pCode.VAULT_MODE_WITHDRAW, asset_type, asset, amount, pCode.STATUS_PENDING]]) .then(result => sendAsset(floID, asset, amount, TYPE_VAULT, result.insertId)) @@ -132,7 +133,7 @@ function withdrawAsset_retry(floID, asset, amount, id) { } function convertToCoin_init(floID, coin, currency_amount, rate, id) { - let coin_quantity = parseFloat((currency_amount / rate).toFixed(8)); + let coin_quantity = global.toStandardDecimal(currency_amount / rate); DB.query("UPDATE DirectConvert SET quantity=?, r_status=?, rate=?, locktime=DEFAULT WHERE id=?", [coin_quantity, pCode.STATUS_PROCESSING, rate, id]) .then(result => sendAsset(floID, coin, coin_quantity, TYPE_CONVERT, id)) .catch(error => console.error(error)) @@ -145,7 +146,7 @@ function convertToCoin_retry(floID, coin, coin_quantity, id) { } function convertFromCoin_init(floID, coin_quantity, rate, id) { - let currency_amount = parseFloat((coin_quantity * rate).toFixed(8)); + let currency_amount = global.toStandardDecimal(coin_quantity * rate); DB.query("UPDATE DirectConvert SET amount=?, r_status=?, rate=?, locktime=DEFAULT WHERE id=?", [currency_amount, pCode.STATUS_PROCESSING, rate, id]) .then(result => sendAsset(floID, floGlobals.currency, currency_amount, TYPE_CONVERT, id)) .catch(error => console.error(error)) @@ -163,29 +164,28 @@ function convertFundWithdraw_retry(asset, amount, id) { else sendAsset(floGlobals.adminID, asset, amount, TYPE_CONVERT_POOL, id); } -function bondTransact_retry(floID, amount, id) { +function bondTransact_retry(floID, amount, btc_rate, usd_rate, id) { if (id in callbackCollection[TYPE_BOND]) console.debug("A callback is already pending for this Bond closing"); - else sendAsset(floID, floGlobals.currency, amount, TYPE_BOND, id); + else sendAsset(floID, "BTC", amount / (btc_rate * usd_rate), TYPE_BOND, id); } - -function fundTransact_retry(floID, amount, id) { +function fundTransact_retry(floID, amount, btc_rate, usd_rate, id) { if (id in callbackCollection[TYPE_FUND]) console.debug("A callback is already pending for this Fund investment closing"); - else sendAsset(floID, floGlobals.currency, amount, TYPE_FUND, id); + else sendAsset(floID, "BTC", amount / (btc_rate * usd_rate), TYPE_FUND, id); } -function refundTransact_init(floID, amount, id) { - amount = parseFloat(amount.toFixed(8)); +function refundTransact_init(floID, asset, amount, id) { + amount = global.toStandardDecimal(amount); DB.query("UPDATE RefundTransact SET amount=?, r_status=?, locktime=DEFAULT WHERE id=?", [amount, pCode.STATUS_PROCESSING, id]) - .then(result => sendAsset(floID, floGlobals.currency, amount, TYPE_REFUND, id)) + .then(result => sendAsset(floID, asset, amount, TYPE_REFUND, id)) .catch(error => console.error(error)) } -function refundTransact_retry(floID, amount, id) { +function refundTransact_retry(floID, asset, amount, id) { if (id in callbackCollection[TYPE_REFUND]) console.debug("A callback is already pending for this Refund"); - else sendAsset(floID, floGlobals.currency, amount, TYPE_REFUND, id); + else sendAsset(floID, asset, amount, TYPE_REFUND, id); } module.exports = { diff --git a/src/coupling.js b/src/coupling.js index d250af9..c9a87e8 100644 --- a/src/coupling.js +++ b/src/coupling.js @@ -34,7 +34,7 @@ function startCouplingForAsset(asset, updatePrice = false) { return; } price.getRates(asset, updatePrice).then(cur_rate => { - cur_rate = cur_rate.toFixed(8); + cur_rate = global.toStandardDecimal(cur_rate); couplingInstance[asset] = true; //set instance as running recursiveCoupling(asset, cur_rate, updatePrice); }).catch(error => console.error(error)); diff --git a/src/market.js b/src/market.js index 8dae1cb..8959692 100644 --- a/src/market.js +++ b/src/market.js @@ -71,7 +71,7 @@ getBalance.floID_token = (floID, token) => new Promise((resolve, reject) => { DB.query("SELECT quantity AS balance FROM UserBalance WHERE floID=? AND token=?", [floID, token]).then(result => resolve({ floID, token, - balance: result.length ? result[0].balance.toFixed(8) : 0 + balance: result.length ? global.toStandardDecimal(result[0].balance) : 0 })).catch(error => reject(error)) }); @@ -82,7 +82,7 @@ getBalance.floID = (floID) => new Promise((resolve, reject) => { balance: {} }; for (let row of result) - response.balance[row.token] = row.balance.toFixed(8); + response.balance[row.token] = global.toStandardDecimal(row.balance); resolve(response); }).catch(error => reject(error)) }); @@ -94,7 +94,7 @@ getBalance.token = (token) => new Promise((resolve, reject) => { balance: {} }; for (let row of result) - response.balance[row.floID] = row.balance.toFixed(8); + response.balance[row.floID] = global.toStandardDecimal(row.balance); resolve(response); }).catch(error => reject(error)) }); diff --git a/src/price.js b/src/price.js index 669e9da..4c43924 100644 --- a/src/price.js +++ b/src/price.js @@ -22,11 +22,11 @@ const updateLastTime = asset => lastTime[asset] = Date.now(); //store FLO price in DB every 1 hr function storeHistory(asset, rate) { - DB.query("INSERT INTO PriceHistory (asset, rate) VALUE (?)", [[asset, rate.toFixed(8)]]) + DB.query("INSERT INTO PriceHistory (asset, rate) VALUE (?)", [[asset, global.toStandardDecimal(rate)]]) .then(_ => null).catch(error => console.error(error)) } -storeHistory.start = function() { +storeHistory.start = function () { storeHistory.stop(); storeHistory.instance = setInterval(() => { for (let asset in currentRate) @@ -34,7 +34,7 @@ storeHistory.start = function() { }, REC_HISTORY_INTERVAL); } -storeHistory.stop = function() { +storeHistory.stop = function () { if (storeHistory.instance !== undefined) { clearInterval(storeHistory.instance); delete storeHistory.instance; @@ -157,8 +157,8 @@ function checkForRatedSellers(asset) { DB.query("SELECT COUNT(*) as value FROM SellOrder WHERE floID IN (" + " SELECT UserTag.floID FROM UserTag INNER JOIN TagList ON UserTag.tag = TagList.tag" + " WHERE TagList.sellPriority > ?) AND asset=?", [ratedMin, asset]).then(result => { - resolve(result[0].value > 0); - }).catch(error => reject(error)) + resolve(result[0].value > 0); + }).catch(error => reject(error)) }).catch(error => reject(error)) }) } diff --git a/src/services/bobs-fund.js b/src/services/bobs-fund.js index f71a74e..7c90a08 100644 --- a/src/services/bobs-fund.js +++ b/src/services/bobs-fund.js @@ -253,7 +253,7 @@ function refreshBlockchainData(nodeList = []) { function closeFund(fund_id, floID, ref) { return new Promise((resolve, reject) => { - DB.query("SELECT r_status, close_id FROM CloseFundTransact WHERE fund_id=?", [fund_id]).then(result => { + DB.query("SELECT r_status, close_id FROM CloseFundTransact WHERE fund_id=? AND floID=?", [fund_id, floID]).then(result => { if (result.length) return reject(INVALID(eCode.DUPLICATE_ENTRY, result[0].r_status == pCode.STATUS_SUCCESS ? `Fund investment already closed (${result[0].close_id})` : `Fund closing already in process`)); DB.query("SELECT * FROM BobsFund WHERE fund_id=?", [fund_id]).then(result => { diff --git a/src/services/conversion.js b/src/services/conversion.js index 44c7987..38b38d0 100644 --- a/src/services/conversion.js +++ b/src/services/conversion.js @@ -96,7 +96,7 @@ function convertToCoin(floID, txid, coin, amount) { }).catch(error => { if (error instanceof INVALID && error.ecode === eCode.INSUFFICIENT_FUND) DB.query("INSERT INTO DirectConvert(floID, in_txid, mode, coin, amount, r_status) VALUES (?)", [[floID, txid, pCode.CONVERT_MODE_GET, coin, amount, pCode.STATUS_REJECTED]]).then(result => { - DB.query("INSERT INTO RefundTransact(floID, in_txid, amount, r_status) VALUES (?)", [[floID, txid, amount, pCode.STATUS_PENDING]]) + DB.query("INSERT INTO RefundTransact(floID, in_txid, asset_type, asset, r_status) VALUES (?)", [[floID, txid, pCode.ASSET_TYPE_TOKEN, floGlobals.currency, pCode.STATUS_PENDING]]) .then(_ => null).catch(error => console.error(error)); }).catch(error => console.error(error)) reject(error); diff --git a/src/set_globals.js b/src/set_globals.js index 20cae60..39756ad 100644 --- a/src/set_globals.js +++ b/src/set_globals.js @@ -13,6 +13,8 @@ try { global[p] = param[p]; } +global.toStandardDecimal = num => (parseInt(num * 1e8) * 1e-8) + if (!process.argv.includes("--debug")) global.console.debug = () => null;