exchangemarket-usd/src/background.js
2022-09-30 05:52:30 +05:30

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
}