200 lines
10 KiB
JavaScript
200 lines
10 KiB
JavaScript
'use strict';
|
|
const blockchain = require('./blockchain');
|
|
|
|
const {
|
|
LAUNCH_SELLER_TAG,
|
|
MAXIMUM_LAUNCH_SELL_CHIPS,
|
|
} = require('./_constants')["market"];
|
|
|
|
function checkTag(floID, tag) {
|
|
return new Promise((resolve, reject) => {
|
|
DB.query("SELECT id FROM UserTag WHERE floID=? AND tag=?", [floID, tag])
|
|
.then(result => resolve(result.length ? true : false))
|
|
.catch(error => reject(error))
|
|
})
|
|
}
|
|
|
|
function confirmDepositFLO() {
|
|
DB.query("SELECT id, floID, txid FROM InputCoin WHERE coin=? AND status=?", ["FLO", "PENDING"]).then(results => {
|
|
results.forEach(req => {
|
|
verifyDepositFLO(req.floID, req.txid).then(amount => {
|
|
addSellChipsIfLaunchSeller(req.floID, amount).then(txQueries => {
|
|
txQueries.push(updateBalance.add(req.floID, "FLO", amount));
|
|
txQueries.push(["UPDATE InputCoin SET status=?, amount=? WHERE id=?", ["SUCCESS", amount, req.id]]);
|
|
DB.transaction(txQueries)
|
|
.then(result => console.debug("FLO deposited:", req.floID, amount))
|
|
.catch(error => console.error(error))
|
|
}).catch(error => console.error(error))
|
|
}).catch(error => {
|
|
console.error(error);
|
|
if (error[0])
|
|
DB.query("UPDATE InputCoin SET status=? WHERE id=?", ["REJECTED", req.id])
|
|
.then(_ => null).catch(error => console.error(error));
|
|
});
|
|
})
|
|
}).catch(error => console.error(error))
|
|
}
|
|
|
|
function verifyDepositFLO(sender, txid) {
|
|
return new Promise((resolve, reject) => {
|
|
floBlockchainAPI.getTx(txid).then(tx => {
|
|
let vin_sender = tx.vin.filter(v => v.addr === sender)
|
|
if (!vin_sender.length)
|
|
return reject([true, "Transaction not sent by the sender"]);
|
|
if (vin_sender.length !== tx.vin.length)
|
|
return reject([true, "Transaction input containes other floIDs"]);
|
|
if (!tx.blockheight)
|
|
return reject([false, "Transaction not included in any block yet"]);
|
|
if (!tx.confirmations)
|
|
return reject([false, "Transaction not confirmed yet"]);
|
|
let amount = tx.vout.reduce((a, v) => blockchain.chests.includes(v.scriptPubKey.addresses[0]) ? a + v.value : a, 0);
|
|
if (amount == 0)
|
|
return reject([true, "Transaction receiver is not market ID"]); //Maybe reject as false? (to compensate delay in chestsList loading from other nodes)
|
|
else
|
|
resolve(amount);
|
|
}).catch(error => reject([false, error]))
|
|
})
|
|
}
|
|
|
|
function addSellChipsIfLaunchSeller(floID, quantity) {
|
|
return new Promise((resolve, reject) => {
|
|
checkTag(floID, LAUNCH_SELLER_TAG).then(result => {
|
|
if (result) //floID is launch-seller
|
|
Promise.all([
|
|
DB.query("SELECT IFNULL(SUM(quantity), 0) AS sold FROM TradeTransactions WHERE seller=? AND asset=?", [floID, 'FLO']),
|
|
DB.query("SELECT IFNULL(SUM(quantity), 0) AS brought FROM TradeTransactions WHERE buyer=? AND asset=?", [floID, 'FLO']),
|
|
DB.query("SELECT IFNULL(SUM(quantity), 0) AS chips FROM SellChips WHERE floID=? AND asset=?", [floID, 'FLO']),
|
|
]).then(result => {
|
|
let sold = result[0][0].sold,
|
|
brought = result[1][0].brought,
|
|
chips = result[2][0].chips;
|
|
let remLaunchChips = MAXIMUM_LAUNCH_SELL_CHIPS - (sold + chips) + brought;
|
|
quantity = Math.min(quantity, remLaunchChips);
|
|
if (quantity > 0)
|
|
resolve([
|
|
["INSERT INTO SellChips(floID, asset, quantity) VALUES (?, ?, ?)", [floID, 'FLO', quantity]]
|
|
]);
|
|
else
|
|
resolve([]);
|
|
}).catch(error => reject(error))
|
|
else //floID is not launch-seller
|
|
resolve([]);
|
|
}).catch(error => reject(error))
|
|
})
|
|
}
|
|
|
|
function confirmDepositToken() {
|
|
DB.query("SELECT id, floID, txid FROM InputToken WHERE status=?", ["PENDING"]).then(results => {
|
|
results.forEach(req => {
|
|
verifyDepositToken(req.floID, req.txid).then(amounts => {
|
|
DB.query("SELECT id FROM InputCoin where floID=? AND coin=? AND txid=?", [req.floID, "FLO", req.txid]).then(result => {
|
|
let txQueries = [],
|
|
token_name = amounts[0],
|
|
amount_token = amounts[1];
|
|
//Add the FLO balance if necessary
|
|
if (!result.length) {
|
|
let amount_flo = amounts[2];
|
|
txQueries.push(updateBalance.add(req.floID, "FLO", amount_flo));
|
|
txQueries.push(["INSERT INTO InputCoin(txid, floID, coin, amount, status) VALUES (?, ?, ?, ?, ?)", [req.txid, req.floID, "FLO", amount_flo, "SUCCESS"]]);
|
|
}
|
|
txQueries.push(["UPDATE InputToken SET status=?, token=?, amount=? WHERE id=?", ["SUCCESS", token_name, amount_token, req.id]]);
|
|
txQueries.push(updateBalance.add(req.floID, token_name, amount_token));
|
|
DB.transaction(txQueries)
|
|
.then(result => console.debug("Token deposited:", req.floID, token_name, amount_token))
|
|
.catch(error => console.error(error));
|
|
}).catch(error => console.error(error));
|
|
}).catch(error => {
|
|
console.error(error);
|
|
if (error[0])
|
|
DB.query("UPDATE InputToken SET status=? WHERE id=?", ["REJECTED", req.id])
|
|
.then(_ => null).catch(error => console.error(error));
|
|
});
|
|
})
|
|
}).catch(error => console.error(error))
|
|
}
|
|
|
|
function verifyDepositToken(sender, txid) {
|
|
return new Promise((resolve, reject) => {
|
|
floTokenAPI.getTx(txid).then(tx => {
|
|
if (tx.parsedFloData.type !== "transfer")
|
|
return reject([true, "Transaction type not 'transfer'"]);
|
|
else if (tx.parsedFloData.transferType !== "token")
|
|
return reject([true, "Transaction transfer is not 'token'"]);
|
|
var token_name = tx.parsedFloData.tokenIdentification,
|
|
amount_token = tx.parsedFloData.tokenAmount;
|
|
if ((!assetList.includes(token_name) && token_name !== floGlobals.currency) || token_name === "FLO")
|
|
return reject([true, "Token not authorised"]);
|
|
let vin_sender = tx.transactionDetails.vin.filter(v => v.addr === sender)
|
|
if (!vin_sender.length)
|
|
return reject([true, "Transaction not sent by the sender"]);
|
|
let amount_flo = tx.transactionDetails.vout.reduce((a, v) => blockchain.chests.includes(v.scriptPubKey.addresses[0]) ? a + v.value : a, 0);
|
|
if (amount_flo == 0)
|
|
return reject([true, "Transaction receiver is not market ID"]); //Maybe reject as false? (to compensate delay in chestsList loading from other nodes)
|
|
else
|
|
resolve([token_name, amount_token, amount_flo]);
|
|
}).catch(error => reject([false, error]))
|
|
})
|
|
}
|
|
|
|
function retryWithdrawalCoin() {
|
|
DB.query("SELECT id, floID, coin, amount FROM OutputCoin WHERE status=?", ["PENDING"]).then(results => {
|
|
results.forEach(req => blockchain.sendCoin.retry(req.floID, req.coin, req.amount, req.id));
|
|
}).catch(error => reject(error));
|
|
}
|
|
|
|
function retryWithdrawalToken() {
|
|
DB.query("SELECT id, floID, token, amount FROM OutputToken WHERE status=?", ["PENDING"]).then(results => {
|
|
results.forEach(req => blockchain.sendToken.retry(req.floID, req.token, req.amount, req.id));
|
|
}).catch(error => reject(error));
|
|
}
|
|
|
|
function confirmWithdrawalFLO() {
|
|
DB.query("SELECT id, floID, amount, txid FROM OutputCoin WHERE coin=? AND status=?", ["FLO", "WAITING_CONFIRMATION"]).then(results => {
|
|
results.forEach(req => {
|
|
floBlockchainAPI.getTx(req.txid).then(tx => {
|
|
if (!tx.blockheight || !tx.confirmations) //Still not confirmed
|
|
return;
|
|
DB.query("UPDATE OutputCoin SET status=? WHERE id=?", ["SUCCESS", req.id])
|
|
.then(result => console.debug("FLO withdrawed:", req.floID, req.amount))
|
|
.catch(error => console.error(error))
|
|
}).catch(error => console.error(error));
|
|
})
|
|
}).catch(error => console.error(error));
|
|
}
|
|
|
|
function confirmWithdrawalBTC() {
|
|
DB.query("SELECT id, floID, amount, txid FROM OutputCoin WHERE coin=? AND status=?", ["BTC", "WAITING_CONFIRMATION"]).then(results => {
|
|
results.forEach(req => {
|
|
btcOperator.getTx(req.txid).then(tx => {
|
|
if (!tx.blockhash || !tx.confirmations) //Still not confirmed
|
|
return;
|
|
DB.query("UPDATE OutputCoin SET status=? WHERE id=?", ["SUCCESS", req.id])
|
|
.then(result => console.debug("BTC withdrawed:", req.floID, req.amount))
|
|
.catch(error => console.error(error))
|
|
}).catch(error => console.error(error));
|
|
})
|
|
}).catch(error => console.error(error));
|
|
}
|
|
|
|
function confirmWithdrawalToken() {
|
|
DB.query("SELECT id, floID, token, amount, txid FROM OutputToken WHERE status=?", ["WAITING_CONFIRMATION"]).then(results => {
|
|
results.forEach(req => {
|
|
floTokenAPI.getTx(req.txid).then(tx => {
|
|
DB.query("UPDATE OutputToken SET status=? WHERE id=?", ["SUCCESS", req.id])
|
|
.then(result => console.debug("Token withdrawed:", req.floID, req.token, req.amount))
|
|
.catch(error => console.error(error));
|
|
}).catch(error => console.error(error));
|
|
})
|
|
}).catch(error => console.error(error));
|
|
}
|
|
|
|
module.exports = {
|
|
blockchain,
|
|
confirmDepositFLO,
|
|
confirmDepositToken,
|
|
retryWithdrawalCoin,
|
|
retryWithdrawalToken,
|
|
confirmWithdrawalFLO,
|
|
confirmWithdrawalBTC,
|
|
confirmWithdrawalToken
|
|
} |