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)
This commit is contained in:
sairajzero 2022-11-05 03:56:40 +05:30
parent 821de1a6d7
commit e4adaf7ed7
10 changed files with 146 additions and 75 deletions

View File

@ -288,6 +288,8 @@ CREATE TABLE DirectConvert(
CREATE TABLE RefundTransact( CREATE TABLE RefundTransact(
id INT NOT NULL AUTO_INCREMENT, id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL, floID CHAR(34) NOT NULL,
asset_type TINYINT NOT NULL,
asset VARCHAR(32) NOT NULL,
amount DECIMAL(16, 8), amount DECIMAL(16, 8),
in_txid VARCHAR(128), in_txid VARCHAR(128),
out_txid VARCHAR(128), out_txid VARCHAR(128),

View File

@ -1,4 +1,4 @@
(function (EXPORTS) { //btcOperator v1.0.12 (function (EXPORTS) { //btcOperator v1.0.13
/* BTC Crypto and API Operator */ /* BTC Crypto and API Operator */
const btcOperator = EXPORTS; const btcOperator = EXPORTS;
@ -307,8 +307,8 @@
parameters.receivers.forEach(id => !validateAddress(id) ? invalids.push(id) : null); parameters.receivers.forEach(id => !validateAddress(id) ? invalids.push(id) : null);
if (invalids.length) if (invalids.length)
throw "Invalid receivers:" + invalids; throw "Invalid receivers:" + invalids;
if (parameters.change_addr && !validateAddress(parameters.change_addr)) if (parameters.change_address && !validateAddress(parameters.change_address))
throw "Invalid change_address:" + parameters.change_addr; throw "Invalid change_address:" + parameters.change_address;
//fee and amounts //fee and amounts
if ((typeof parameters.fee !== "number" || parameters.fee <= 0) && parameters.fee !== null) //fee = null (auto calc) if ((typeof parameters.fee !== "number" || parameters.fee <= 0) && parameters.fee !== null) //fee = null (auto calc)
throw "Invalid fee:" + parameters.fee; throw "Invalid fee:" + parameters.fee;
@ -323,16 +323,29 @@
return parameters; 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) => { return new Promise((resolve, reject) => {
let total_amount = parseFloat(amounts.reduce((t, a) => t + a, 0).toFixed(8)); let total_amount = parseFloat(amounts.reduce((t, a) => t + a, 0).toFixed(8));
const tx = coinjs.transaction(); 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 => { 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 tx.outs[tx.outs.length - 1].value = parseInt(result.change_amount * SATOSHI_IN_BTC); //values are in satoshi
else if (fee_from_receiver) { //deduce fee from receivers if fee_from_receiver
tx.outs.pop(); //remove the change output if no change_amount 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_size = output_size;
result.output_amount = total_amount; result.output_amount = total_amount;
result.total_size = BASE_TX_SIZE + output_size + result.input_size; 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) => { return new Promise((resolve, reject) => {
if (fee !== null) { 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; result.fee = fee;
resolve(result); resolve(result);
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -353,7 +366,10 @@
get_fee_rate().then(fee_rate => { get_fee_rate().then(fee_rate => {
let net_fee = BASE_TX_SIZE * fee_rate; let net_fee = BASE_TX_SIZE * fee_rate;
net_fee += (output_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 = parseFloat((net_fee + (result.input_size * fee_rate)).toFixed(8));
result.fee_rate = fee_rate; result.fee_rate = fee_rate;
resolve(result); resolve(result);
@ -416,14 +432,14 @@
}) })
} }
function addOutputs(tx, receivers, amounts, change_addr) { function addOutputs(tx, receivers, amounts, change_address) {
let size = 0; let size = 0;
for (let i in receivers) { for (let i in receivers) {
tx.addoutput(receivers[i], amounts[i]); tx.addoutput(receivers[i], amounts[i]);
size += _sizePerOutput(receivers[i]); size += _sizePerOutput(receivers[i]);
} }
tx.addoutput(change_addr, 0); tx.addoutput(change_address, 0);
size += _sizePerOutput(change_addr); size += _sizePerOutput(change_address);
return size; 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) => { 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; debugger;
broadcastTx(result.transaction.serialize()) broadcastTx(result.transaction.serialize())
.then(txid => resolve(txid)) .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) => { return new Promise((resolve, reject) => {
try { try {
({ ({
@ -489,7 +505,7 @@
receivers, receivers,
amounts, amounts,
fee, fee,
change_addr change_address: options.change_address
})); }));
} catch (e) { } catch (e) {
return reject(e) return reject(e)
@ -504,7 +520,7 @@
if (redeemScripts.includes(null)) //TODO: segwit if (redeemScripts.includes(null)) //TODO: segwit
return reject("Unable to get redeem-script"); return reject("Unable to get redeem-script");
//create transaction //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; let tx = result.transaction;
console.debug("Unsigned:", tx.serialize()); 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 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) => { return new Promise((resolve, reject) => {
try { try {
({ ({
@ -526,7 +542,7 @@
receivers, receivers,
amounts, amounts,
fee, fee,
change_addr change_address: options.change_address
})); }));
} catch (e) { } catch (e) {
return reject(e) return reject(e)
@ -535,7 +551,7 @@
if (redeemScripts.includes(null)) //TODO: segwit if (redeemScripts.includes(null)) //TODO: segwit
return reject("Unable to get redeem-script"); return reject("Unable to get redeem-script");
//create transaction //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(); result.tx_hex = result.transaction.serialize();
delete result.transaction; delete result.transaction;
resolve(result); 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) => { return new Promise((resolve, reject) => {
//validate tx parameters //validate tx parameters
if (validateAddress(sender) !== "multisig") if (validateAddress(sender) !== "multisig")
@ -561,13 +577,14 @@
} = validateTxParameters({ } = validateTxParameters({
receivers, receivers,
amounts, amounts,
fee fee,
change_address: options.change_address
})); }));
} catch (e) { } catch (e) {
return reject(e) return reject(e)
} }
//create transaction //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(); result.tx_hex = result.transaction.serialize();
delete result.transaction; delete result.transaction;
resolve(result); resolve(result);

View File

@ -152,7 +152,7 @@ function retryVaultWithdrawal() {
} else if (r.asset_type == pCode.ASSET_TYPE_TOKEN) } else if (r.asset_type == pCode.ASSET_TYPE_TOKEN)
blockchain.withdrawAsset.retry(r.floID, r.asset, r.amount, r.id) blockchain.withdrawAsset.retry(r.floID, r.asset, r.amount, r.id)
}) })
}).catch(error => reject(error)) }).catch(error => console.error(error))
} }
function confirmVaultWithdraw() { function confirmVaultWithdraw() {
@ -210,7 +210,16 @@ verifyTx.BTC = function (sender, txid) {
} }
function verifyConvert() { function verifyConvert() {
DB.query("UPDATE DirectConvert SET r_status=? WHERE r_status=? AND locktime<?", [pCode.STATUS_REJECTED, pCode.STATUS_PENDING, new Date(Date.now() - REQUEST_TIMEOUT)]).then(result => { //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<? AND mode=?";
let txQueries = [];
txQueries.push([to_refund_sql, [pCode.ASSET_TYPE_TOKEN, floGlobals.currency, pCode.STATUS_PENDING, req_timeout, pCode.CONVERT_MODE_GET]]);
txQueries.push([to_refund_sql, [pCode.ASSET_TYPE_COIN, "BTC", pCode.STATUS_PENDING, req_timeout, pCode.CONVERT_MODE_PUT]]);
txQueries.push(["UPDATE DirectConvert SET r_status=? WHERE r_status=? AND locktime<?", [pCode.STATUS_REJECTED, pCode.STATUS_PENDING, req_timeout]]);
DB.transaction(txQueries).then(result => {
DB.query("SELECT id, floID, mode, in_txid, amount, quantity FROM DirectConvert WHERE r_status=? AND coin=?", [pCode.STATUS_PENDING, "BTC"]).then(results => { 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 => { results.forEach(r => {
if (r.mode == pCode.CONVERT_MODE_GET) { if (r.mode == pCode.CONVERT_MODE_GET) {
@ -242,7 +251,7 @@ function verifyConvert() {
} }
}) })
}).catch(error => console.error(error)) }).catch(error => console.error(error))
}).catch(error => reject(error)) }).catch(error => console.error(error))
} }
function retryConvert() { function retryConvert() {
@ -345,11 +354,34 @@ function confirmConvertFundWithdraw() {
} }
function verifyRefund() { 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 => { results.forEach(r => {
verifyTx.token(r.floID, r.in_txid, true) if (r.ASSET_TYPE_COIN) {
.then(({ amount }) => blockchain.refundTransact.init(r.floID, amount, r.id)) if (r.asset == "FLO")
.catch(error => { 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); console.error(error);
if (error[0]) if (error[0])
DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_REJECTED, r.id]) DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_REJECTED, r.id])
@ -360,36 +392,54 @@ function verifyRefund() {
} }
function retryRefund() { function retryRefund() {
DB.query("SELECT id, floID, amount FROM RefundTransact WHERE r_status=?", [pCode.STATUS_PROCESSING]).then(results => { 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.amount, r.id)) results.forEach(r => blockchain.refundTransact.retry(r.floID, r.asset, r.amount, r.id))
}).catch(error => console.error(error)) }).catch(error => console.error(error))
} }
function confirmRefund() { function confirmRefund() {
DB.query("SELECT * FROM RefundTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => { DB.query("SELECT * FROM RefundTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => {
results.forEach(r => { results.forEach(r => { //TODO
floTokenAPI.getTx(r.out_txid).then(tx => { if (r.ASSET_TYPE_COIN) {
if (!tx.transactionDetails.blockheight || !tx.transactionDetails.confirmations) //Still not confirmed if (r.asset == "FLO")
return; floBlockchainAPI.getTx(r.out_txid).then(tx => {
DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_SUCCESS, r.id]) if (!tx.blockheight || !tx.confirmations) //Still not confirmed
.then(result => console.info(`Refunded ${r.amount} to ${r.floID}`)) return;
.catch(error => console.error(error)); DB.query("UPDATE RefundTransact SET r_status=? WHERE id=?", [pCode.STATUS_SUCCESS, r.id])
}).catch(error => console.error(error)); .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)) }).catch(error => console.error(error))
} }
function retryBondClosing() { function retryBondClosing() {
DB.query("SELECT id, floID, amount FROM CloseBondTransact WHERE r_status=?", [pCode.STATUS_PENDING]).then(results => { 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.id)) results.forEach(r => blockchain.bondTransact.retry(r.floID, r.amount, r.btc_net, r.usd_net, r.id))
}).catch(error => console.error(error)) }).catch(error => console.error(error))
} }
function confirmBondClosing() { function confirmBondClosing() {
DB.query("SELECT * FROM CloseBondTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => { DB.query("SELECT * FROM CloseBondTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => {
results.forEach(r => { results.forEach(r => {
floTokenAPI.getTx(r.txid).then(tx => { btcOperator.getTx(r.txid).then(tx => {
if (!tx.transactionDetails.blockheight || !tx.transactionDetails.confirmations) //Still not confirmed if (!tx.blockhash || !tx.confirmations) //Still not confirmed
return; 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); 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 => { floBlockchainAPI.writeData(global.myFloID, closeBondString, global.myPrivKey, bond_util.config.adminID).then(txid => {
@ -403,16 +453,16 @@ function confirmBondClosing() {
} }
function retryFundClosing() { function retryFundClosing() {
DB.query("SELECT id, floID, amount FROM CloseFundTransact WHERE r_status=?", [pCode.STATUS_PENDING]).then(results => { 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.id)) results.forEach(r => blockchain.fundTransact.retry(r.floID, r.amount, r.btc_net, r.usd_net, r.id))
}).catch(error => console.error(error)) }).catch(error => console.error(error))
} }
function confirmFundClosing() { function confirmFundClosing() {
DB.query("SELECT * FROM CloseFundTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => { DB.query("SELECT * FROM CloseFundTransact WHERE r_status=?", [pCode.STATUS_CONFIRMATION]).then(results => {
results.forEach(r => { results.forEach(r => {
floTokenAPI.getTx(r.txid).then(tx => { btcOperator.getTx(r.txid).then(tx => {
if (!tx.transactionDetails.blockheight || !tx.transactionDetails.confirmations) //Still not confirmed if (!tx.blockhash || !tx.confirmations) //Still not confirmed
return; 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); 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 => { floBlockchainAPI.writeData(global.myFloID, closeFundString, global.myPrivKey, fund_util.config.adminID).then(txid => {

View File

@ -79,7 +79,7 @@ function sendTx(floID, asset, quantity, sinkID, sinkKey, message) {
case "BTC": case "BTC":
let btc_sinkID = btcOperator.convert.legacy2bech(sinkID), let btc_sinkID = btcOperator.convert.legacy2bech(sinkID),
btc_receiver = btcOperator.convert.legacy2bech(floID); 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: default:
return floTokenAPI.sendToken(sinkKey, quantity, floID, message, asset); return floTokenAPI.sendToken(sinkKey, quantity, floID, message, asset);
} }
@ -95,6 +95,7 @@ const updateSyntax = {
}; };
function sendAsset(floID, asset, quantity, type, id) { function sendAsset(floID, asset, quantity, type, id) {
quantity = global.toStandardDecimal(quantity);
getSinkID(quantity, asset).then(sinkID => { getSinkID(quantity, asset).then(sinkID => {
let callback = (sinkKey) => { let callback = (sinkKey) => {
//Send asset to user via API //Send asset to user via API
@ -118,7 +119,7 @@ function sendAsset(floID, asset, quantity, type, id) {
} }
function withdrawAsset_init(floID, asset, amount) { 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; 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]]) 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)) .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) { 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]) 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)) .then(result => sendAsset(floID, coin, coin_quantity, TYPE_CONVERT, id))
.catch(error => console.error(error)) .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) { 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]) 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)) .then(result => sendAsset(floID, floGlobals.currency, currency_amount, TYPE_CONVERT, id))
.catch(error => console.error(error)) .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); 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]) if (id in callbackCollection[TYPE_BOND])
console.debug("A callback is already pending for this Bond closing"); 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, btc_rate, usd_rate, id) {
function fundTransact_retry(floID, amount, id) {
if (id in callbackCollection[TYPE_FUND]) if (id in callbackCollection[TYPE_FUND])
console.debug("A callback is already pending for this Fund investment closing"); 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) { function refundTransact_init(floID, asset, amount, id) {
amount = parseFloat(amount.toFixed(8)); amount = global.toStandardDecimal(amount);
DB.query("UPDATE RefundTransact SET amount=?, r_status=?, locktime=DEFAULT WHERE id=?", [amount, pCode.STATUS_PROCESSING, id]) 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)) .catch(error => console.error(error))
} }
function refundTransact_retry(floID, amount, id) { function refundTransact_retry(floID, asset, amount, id) {
if (id in callbackCollection[TYPE_REFUND]) if (id in callbackCollection[TYPE_REFUND])
console.debug("A callback is already pending for this 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 = { module.exports = {

View File

@ -34,7 +34,7 @@ function startCouplingForAsset(asset, updatePrice = false) {
return; return;
} }
price.getRates(asset, updatePrice).then(cur_rate => { 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 couplingInstance[asset] = true; //set instance as running
recursiveCoupling(asset, cur_rate, updatePrice); recursiveCoupling(asset, cur_rate, updatePrice);
}).catch(error => console.error(error)); }).catch(error => console.error(error));

View File

@ -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({ DB.query("SELECT quantity AS balance FROM UserBalance WHERE floID=? AND token=?", [floID, token]).then(result => resolve({
floID, floID,
token, token,
balance: result.length ? result[0].balance.toFixed(8) : 0 balance: result.length ? global.toStandardDecimal(result[0].balance) : 0
})).catch(error => reject(error)) })).catch(error => reject(error))
}); });
@ -82,7 +82,7 @@ getBalance.floID = (floID) => new Promise((resolve, reject) => {
balance: {} balance: {}
}; };
for (let row of result) for (let row of result)
response.balance[row.token] = row.balance.toFixed(8); response.balance[row.token] = global.toStandardDecimal(row.balance);
resolve(response); resolve(response);
}).catch(error => reject(error)) }).catch(error => reject(error))
}); });
@ -94,7 +94,7 @@ getBalance.token = (token) => new Promise((resolve, reject) => {
balance: {} balance: {}
}; };
for (let row of result) for (let row of result)
response.balance[row.floID] = row.balance.toFixed(8); response.balance[row.floID] = global.toStandardDecimal(row.balance);
resolve(response); resolve(response);
}).catch(error => reject(error)) }).catch(error => reject(error))
}); });

View File

@ -22,11 +22,11 @@ const updateLastTime = asset => lastTime[asset] = Date.now();
//store FLO price in DB every 1 hr //store FLO price in DB every 1 hr
function storeHistory(asset, rate) { 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)) .then(_ => null).catch(error => console.error(error))
} }
storeHistory.start = function() { storeHistory.start = function () {
storeHistory.stop(); storeHistory.stop();
storeHistory.instance = setInterval(() => { storeHistory.instance = setInterval(() => {
for (let asset in currentRate) for (let asset in currentRate)
@ -34,7 +34,7 @@ storeHistory.start = function() {
}, REC_HISTORY_INTERVAL); }, REC_HISTORY_INTERVAL);
} }
storeHistory.stop = function() { storeHistory.stop = function () {
if (storeHistory.instance !== undefined) { if (storeHistory.instance !== undefined) {
clearInterval(storeHistory.instance); clearInterval(storeHistory.instance);
delete storeHistory.instance; delete storeHistory.instance;
@ -157,8 +157,8 @@ function checkForRatedSellers(asset) {
DB.query("SELECT COUNT(*) as value FROM SellOrder WHERE floID IN (" + DB.query("SELECT COUNT(*) as value FROM SellOrder WHERE floID IN (" +
" SELECT UserTag.floID FROM UserTag INNER JOIN TagList ON UserTag.tag = TagList.tag" + " SELECT UserTag.floID FROM UserTag INNER JOIN TagList ON UserTag.tag = TagList.tag" +
" WHERE TagList.sellPriority > ?) AND asset=?", [ratedMin, asset]).then(result => { " WHERE TagList.sellPriority > ?) AND asset=?", [ratedMin, asset]).then(result => {
resolve(result[0].value > 0); resolve(result[0].value > 0);
}).catch(error => reject(error)) }).catch(error => reject(error))
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
} }

View File

@ -253,7 +253,7 @@ function refreshBlockchainData(nodeList = []) {
function closeFund(fund_id, floID, ref) { function closeFund(fund_id, floID, ref) {
return new Promise((resolve, reject) => { 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) 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`)); 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 => { DB.query("SELECT * FROM BobsFund WHERE fund_id=?", [fund_id]).then(result => {

View File

@ -96,7 +96,7 @@ function convertToCoin(floID, txid, coin, amount) {
}).catch(error => { }).catch(error => {
if (error instanceof INVALID && error.ecode === eCode.INSUFFICIENT_FUND) 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 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)); .then(_ => null).catch(error => console.error(error));
}).catch(error => console.error(error)) }).catch(error => console.error(error))
reject(error); reject(error);

View File

@ -13,6 +13,8 @@ try {
global[p] = param[p]; global[p] = param[p];
} }
global.toStandardDecimal = num => (parseInt(num * 1e8) * 1e-8)
if (!process.argv.includes("--debug")) if (!process.argv.includes("--debug"))
global.console.debug = () => null; global.console.debug = () => null;