Adding support for BTC withdrawal
This commit is contained in:
parent
d2f1ba8cda
commit
bdd79a1a76
@ -114,19 +114,21 @@ CREATE TABLE BuyOrder (
|
|||||||
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE InputFLO (
|
CREATE TABLE InputCoin (
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
txid VARCHAR(128) NOT NULL,
|
txid VARCHAR(128) NOT NULL,
|
||||||
floID CHAR(34) NOT NULL,
|
floID CHAR(34) NOT NULL,
|
||||||
|
coin VARCHAR(8) NOT NULL,
|
||||||
amount DECIMAL(16, 8),
|
amount DECIMAL(16, 8),
|
||||||
status VARCHAR(50) NOT NULL,
|
status VARCHAR(50) NOT NULL,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE OutputFLO (
|
CREATE TABLE OutputCoin (
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
txid VARCHAR(128),
|
txid VARCHAR(128),
|
||||||
floID CHAR(34) NOT NULL,
|
floID CHAR(34) NOT NULL,
|
||||||
|
coin VARCHAR(8) NOT NULL,
|
||||||
amount DECIMAL(16, 8) NOT NULL,
|
amount DECIMAL(16, 8) NOT NULL,
|
||||||
status VARCHAR(50) NOT NULL,
|
status VARCHAR(50) NOT NULL,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
@ -146,7 +148,7 @@ CREATE TABLE OutputToken (
|
|||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
txid VARCHAR(128),
|
txid VARCHAR(128),
|
||||||
floID CHAR(34) NOT NULL,
|
floID CHAR(34) NOT NULL,
|
||||||
token VARCHAR(64),
|
token VARCHAR(64) NOT NULL,
|
||||||
amount DECIMAL(16, 8) NOT NULL,
|
amount DECIMAL(16, 8) NOT NULL,
|
||||||
status VARCHAR(50) NOT NULL,
|
status VARCHAR(50) NOT NULL,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
@ -277,19 +279,19 @@ FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('BuyOrder', NEW.id) ON DUP
|
|||||||
CREATE TRIGGER BuyOrder_D AFTER DELETE ON BuyOrder
|
CREATE TRIGGER BuyOrder_D AFTER DELETE ON BuyOrder
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('BuyOrder', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('BuyOrder', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
||||||
|
|
||||||
CREATE TRIGGER InputFLO_I AFTER INSERT ON InputFLO
|
CREATE TRIGGER InputCoin_I AFTER INSERT ON InputCoin
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputCoin', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER InputFLO_U AFTER UPDATE ON InputFLO
|
CREATE TRIGGER InputCoin_U AFTER UPDATE ON InputCoin
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputCoin', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER InputFLO_D AFTER DELETE ON InputFLO
|
CREATE TRIGGER InputCoin_D AFTER DELETE ON InputCoin
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputFLO', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputCoin', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
||||||
|
|
||||||
CREATE TRIGGER OutputFLO_I AFTER INSERT ON OutputFLO
|
CREATE TRIGGER OutputCoin_I AFTER INSERT ON OutputCoin
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputCoin', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER OutputFLO_U AFTER UPDATE ON OutputFLO
|
CREATE TRIGGER OutputCoin_U AFTER UPDATE ON OutputCoin
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputCoin', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER OutputFLO_D AFTER DELETE ON OutputFLO
|
CREATE TRIGGER OutputCoin_D AFTER DELETE ON OutputCoin
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputFLO', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputCoin', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
||||||
|
|
||||||
CREATE TRIGGER InputToken_I AFTER INSERT ON InputToken
|
CREATE TRIGGER InputToken_I AFTER INSERT ON InputToken
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
|
|||||||
@ -4,9 +4,9 @@ TRUNCATE _backupCache;
|
|||||||
TRUNCATE AuditTrade;
|
TRUNCATE AuditTrade;
|
||||||
TRUNCATE BuyOrder;
|
TRUNCATE BuyOrder;
|
||||||
TRUNCATE Distributors;
|
TRUNCATE Distributors;
|
||||||
TRUNCATE InputFLO;
|
TRUNCATE InputCoin;
|
||||||
TRUNCATE InputToken;
|
TRUNCATE InputToken;
|
||||||
TRUNCATE OutputFLO;
|
TRUNCATE OutputCoin;
|
||||||
TRUNCATE OutputToken;
|
TRUNCATE OutputToken;
|
||||||
TRUNCATE PriceHistory;
|
TRUNCATE PriceHistory;
|
||||||
TRUNCATE RequestLog;
|
TRUNCATE RequestLog;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
(function(EXPORTS) { //btcOperator v1.0.10
|
(function(EXPORTS) { //btcOperator v1.0.10a
|
||||||
/* BTC Crypto and API Operator */
|
/* BTC Crypto and API Operator */
|
||||||
const btcOperator = EXPORTS;
|
const btcOperator = EXPORTS;
|
||||||
|
|
||||||
@ -31,16 +31,16 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const broadcast = btcOperator.broadcast = rawtx => new Promise((resolve, reject) => {
|
const broadcastTx = btcOperator.broadcastTx = rawTxHex => new Promise((resolve, reject) => {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: URL + "send_tx/BTC/",
|
url: URL + "send_tx/BTC/",
|
||||||
data: {
|
data: {
|
||||||
"tx_hex": rawtx
|
"tx_hex": rawTxHex
|
||||||
},
|
},
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
error: e => reject(e.responseJSON),
|
error: e => reject(e.responseJSON),
|
||||||
success: r => r.status === "success" ? resolve(r.data) : reject(r)
|
success: r => r.status === "success" ? resolve(r.data.txid) : reject(r)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -485,8 +485,8 @@
|
|||||||
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
|
||||||
console.debug("Signed:", tx.serialize());
|
console.debug("Signed:", tx.serialize());
|
||||||
debugger;
|
debugger;
|
||||||
broadcast(tx.serialize())
|
broadcastTx(tx.serialize())
|
||||||
.then(result => resolve(result))
|
.then(txid => resolve(txid))
|
||||||
.catch(error => reject(error));
|
.catch(error => reject(error));
|
||||||
}).catch(error => reject(error));
|
}).catch(error => reject(error));
|
||||||
})
|
})
|
||||||
|
|||||||
200
src/background.js
Normal file
200
src/background.js
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
'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
|
||||||
|
}
|
||||||
@ -3,14 +3,28 @@
|
|||||||
var collectAndCall; //container for collectAndCall function from backup module
|
var collectAndCall; //container for collectAndCall function from backup module
|
||||||
var chests; //container for blockchain ids (where assets are stored)
|
var chests; //container for blockchain ids (where assets are stored)
|
||||||
|
|
||||||
|
const WITHDRAWAL_MESSAGE = "(withdrawal from market)";
|
||||||
|
|
||||||
const balance_locked = {},
|
const balance_locked = {},
|
||||||
balance_cache = {},
|
balance_cache = {},
|
||||||
callbackCollection = {
|
callbackCollection = {
|
||||||
FLO: {},
|
Coin: {},
|
||||||
token: {}
|
token: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
function getSinkID(amount, asset = "FLO", sinkList = null) {
|
function getBalance(sinkID, asset) {
|
||||||
|
switch (asset) {
|
||||||
|
case "FLO":
|
||||||
|
return floBlockchainAPI.getBalance(sinkID);
|
||||||
|
case "BTC":
|
||||||
|
let btc_id = btcOperator.convert.legacy2bech(sinkID);
|
||||||
|
return btcOperator.getBalance(btc_id);
|
||||||
|
default:
|
||||||
|
return floTokenAPI.getBalance(sinkID, asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSinkID(amount, asset, sinkList = null) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!sinkList)
|
if (!sinkList)
|
||||||
sinkList = chests.list.map(s => [s, s in balance_cache ? balance_cache[s][asset] || 0 : 0]) //TODO: improve sorting
|
sinkList = chests.list.map(s => [s, s in balance_cache ? balance_cache[s][asset] || 0 : 0]) //TODO: improve sorting
|
||||||
@ -18,7 +32,7 @@ function getSinkID(amount, asset = "FLO", sinkList = null) {
|
|||||||
if (!sinkList.length)
|
if (!sinkList.length)
|
||||||
return reject(`Insufficient balance in chests for asset(${asset})`);
|
return reject(`Insufficient balance in chests for asset(${asset})`);
|
||||||
let sinkID = sinkList.shift();
|
let sinkID = sinkList.shift();
|
||||||
(asset === "FLO" ? floBlockchainAPI.getBalance(sinkID) : floTokenAPI.getBalance(sinkID, asset)).then(balance => {
|
getBalance(sinkID, asset).then(balance => {
|
||||||
if (!(sinkID in balance_cache))
|
if (!(sinkID in balance_cache))
|
||||||
balance_cache[sinkID] = {};
|
balance_cache[sinkID] = {};
|
||||||
balance_cache[sinkID][asset] = balance;
|
balance_cache[sinkID][asset] = balance;
|
||||||
@ -37,47 +51,55 @@ function getSinkID(amount, asset = "FLO", sinkList = null) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendFLO(floID, amount, id) {
|
function sendTx(floID, coin, amount, sinkID, sinkKey) {
|
||||||
getSinkID(amount).then(sinkID => {
|
switch (coin) {
|
||||||
|
case "FLO":
|
||||||
|
return floBlockchainAPI.sendTx(sinkID, floID, amount, sinkKey, WITHDRAWAL_MESSAGE);
|
||||||
|
case "BTC":
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendCoin(floID, coin, amount, id) {
|
||||||
|
getSinkID(amount, coin).then(sinkID => {
|
||||||
let callback = (sinkKey) => {
|
let callback = (sinkKey) => {
|
||||||
//Send FLO to user via blockchain API
|
//Send Coin to user via blockchain API
|
||||||
floBlockchainAPI.sendTx(sinkID, floID, amount, sinkKey, '(withdrawal from market)').then(txid => {
|
sendTx(floID, coin, amount, sinkID, sinkKey).then(txid => {
|
||||||
if (!txid)
|
if (!txid)
|
||||||
throw Error("Transaction not successful");
|
throw Error("Transaction not successful");
|
||||||
//Transaction was successful, Add in DB
|
//Transaction was successful, Add in DB
|
||||||
DB.query("UPDATE OutputFLO SET status=?, txid=? WHERE id=?", ["WAITING_CONFIRMATION", txid, id])
|
DB.query("UPDATE OutputCoin SET status=?, txid=? WHERE id=?", ["WAITING_CONFIRMATION", txid, id])
|
||||||
.then(_ => null).catch(error => console.error(error));
|
.then(_ => null).catch(error => console.error(error));
|
||||||
}).catch(error => console.error(error)).finally(_ => {
|
}).catch(error => console.error(error)).finally(_ => {
|
||||||
delete callbackCollection.FLO[id];
|
delete callbackCollection.Coin[id];
|
||||||
balance_locked[sinkID].FLO -= amount;
|
balance_locked[sinkID][coin] -= amount;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
collectAndCall(sinkID, callback);
|
collectAndCall(sinkID, callback);
|
||||||
callbackCollection.FLO[id] = callback;
|
callbackCollection.Coin[id] = callback;
|
||||||
if (!(sinkID in balance_locked))
|
if (!(sinkID in balance_locked))
|
||||||
balance_locked[sinkID] = {};
|
balance_locked[sinkID] = {};
|
||||||
balance_locked[sinkID].FLO = (balance_locked[sinkID].FLO || 0) + amount;
|
balance_locked[sinkID][coin] = (balance_locked[sinkID][coin] || 0) + amount;
|
||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendFLO_init(floID, amount) {
|
function sendCoin_init(floID, coin, amount) {
|
||||||
DB.query("INSERT INTO OutputFLO (floID, amount, status) VALUES (?, ?, ?)", [floID, amount, "PENDING"])
|
DB.query("INSERT INTO OutputCoin (floID, coin, amount, status) VALUES (?, ?, ?, ?)", [floID, coin, amount, "PENDING"])
|
||||||
.then(result => sendFLO(floID, amount, result.insertId))
|
.then(result => sendCoin(floID, coin, amount, result.insertId))
|
||||||
.catch(error => console.error(error))
|
.catch(error => console.error(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendFLO_retry(floID, amount, id) {
|
function sendCoin_retry(floID, coin, amount, id) {
|
||||||
if (id in callbackCollection.FLO)
|
if (id in callbackCollection.Coin)
|
||||||
console.debug("A callback is already pending for this FLO transfer");
|
console.debug("A callback is already pending for this FLO transfer");
|
||||||
else
|
else
|
||||||
sendFLO(floID, amount, id);
|
sendCoin(floID, coin, amount, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendToken(floID, token, amount, id) {
|
function sendToken(floID, token, amount, id) {
|
||||||
getSinkID(amount, token).then(sinkID => {
|
getSinkID(amount, token).then(sinkID => {
|
||||||
let callback = (sinkKey) => {
|
let callback = (sinkKey) => {
|
||||||
//Send Token to user via token API
|
//Send Token to user via token API
|
||||||
floTokenAPI.sendToken(sinkKey, amount, floID, '(withdrawal from market)', token).then(txid => {
|
floTokenAPI.sendToken(sinkKey, amount, floID, WITHDRAWAL_MESSAGE, token).then(txid => {
|
||||||
if (!txid)
|
if (!txid)
|
||||||
throw Error("Transaction not successful");
|
throw Error("Transaction not successful");
|
||||||
//Transaction was successful, Add in DB
|
//Transaction was successful, Add in DB
|
||||||
@ -96,7 +118,7 @@ function sendToken(floID, token, amount, id) {
|
|||||||
}).catch(error => console.error(error))
|
}).catch(error => console.error(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendToken_init() {
|
function sendToken_init(floID, token, amount) {
|
||||||
DB.query("INSERT INTO OutputToken (floID, token, amount, status) VALUES (?, ?, ?, ?)", [floID, token, amount, "PENDING"])
|
DB.query("INSERT INTO OutputToken (floID, token, amount, status) VALUES (?, ?, ?, ?)", [floID, token, amount, "PENDING"])
|
||||||
.then(result => sendToken(floID, amount, result.insertId))
|
.then(result => sendToken(floID, amount, result.insertId))
|
||||||
.catch(error => console.error(error))
|
.catch(error => console.error(error))
|
||||||
@ -119,9 +141,9 @@ module.exports = {
|
|||||||
set chests(c) {
|
set chests(c) {
|
||||||
chests = c;
|
chests = c;
|
||||||
},
|
},
|
||||||
sendFLO: {
|
sendCoin: {
|
||||||
init: sendFLO_init,
|
init: sendCoin_init,
|
||||||
retry: sendFLO_retry
|
retry: sendCoin_retry
|
||||||
},
|
},
|
||||||
sendToken: {
|
sendToken: {
|
||||||
init: sendToken_init,
|
init: sendToken_init,
|
||||||
|
|||||||
196
src/market.js
196
src/market.js
@ -1,13 +1,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const coupling = require('./coupling');
|
const coupling = require('./coupling');
|
||||||
const blockchain = require('./blockchain');
|
const background = require('./background');
|
||||||
|
const blockchain = background.blockchain;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
PERIOD_INTERVAL,
|
PERIOD_INTERVAL,
|
||||||
WAIT_TIME,
|
WAIT_TIME,
|
||||||
LAUNCH_SELLER_TAG,
|
|
||||||
MAXIMUM_LAUNCH_SELL_CHIPS,
|
|
||||||
TRADE_HASH_PREFIX,
|
TRADE_HASH_PREFIX,
|
||||||
TRANSFER_HASH_PREFIX
|
TRANSFER_HASH_PREFIX
|
||||||
} = require('./_constants')["market"];
|
} = require('./_constants')["market"];
|
||||||
@ -258,9 +257,9 @@ function getAccountDetails(floID) {
|
|||||||
function getUserTransacts(floID) {
|
function getUserTransacts(floID) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
DB.query("(SELECT 'deposit' as type, txid, token, amount, status FROM InputToken WHERE floID=?)" +
|
DB.query("(SELECT 'deposit' as type, txid, token, amount, status FROM InputToken WHERE floID=?)" +
|
||||||
"UNION (SELECT 'deposit' as type, txid, 'FLO' as token, amount, status FROM InputFLO WHERE floID=?)" +
|
"UNION (SELECT 'deposit' as type, txid, coin as token, amount, status FROM InputCoin WHERE floID=?)" +
|
||||||
"UNION (SELECT 'withdraw' as type, txid, token, amount, status FROM OutputToken WHERE floID=?)" +
|
"UNION (SELECT 'withdraw' as type, txid, token, amount, status FROM OutputToken WHERE floID=?)" +
|
||||||
"UNION (SELECT 'withdraw' as type, txid, 'FLO' as token, amount, status FROM OutputFLO WHERE floID=?)",
|
"UNION (SELECT 'withdraw' as type, txid, coin as token, amount, status FROM OutputCoin WHERE floID=?)",
|
||||||
[floID, floID, floID, floID])
|
[floID, floID, floID, floID])
|
||||||
.then(result => resolve(result))
|
.then(result => resolve(result))
|
||||||
.catch(error => reject(error))
|
.catch(error => reject(error))
|
||||||
@ -339,7 +338,7 @@ function transferToken(sender, receivers, token) {
|
|||||||
|
|
||||||
function depositFLO(floID, txid) {
|
function depositFLO(floID, txid) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
DB.query("SELECT status FROM InputFLO WHERE txid=? AND floID=?", [txid, floID]).then(result => {
|
DB.query("SELECT status FROM InputCoin WHERE txid=? AND floID=? AND coin=?", [txid, floID, "FLO"]).then(result => {
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
switch (result[0].status) {
|
switch (result[0].status) {
|
||||||
case "PENDING":
|
case "PENDING":
|
||||||
@ -350,82 +349,13 @@ function depositFLO(floID, txid) {
|
|||||||
return reject(INVALID(eCode.DUPLICATE_ENTRY, "Transaction already used to add coins"));
|
return reject(INVALID(eCode.DUPLICATE_ENTRY, "Transaction already used to add coins"));
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
DB.query("INSERT INTO InputFLO(txid, floID, status) VALUES (?, ?, ?)", [txid, floID, "PENDING"])
|
DB.query("INSERT INTO InputCoin(txid, floID, coin, status) VALUES (?, ?, ?, ?)", [txid, floID, "FLO", "PENDING"])
|
||||||
.then(result => resolve("Deposit request in process"))
|
.then(result => resolve("Deposit request in process"))
|
||||||
.catch(error => reject(error));
|
.catch(error => reject(error));
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmDepositFLO() {
|
|
||||||
DB.query("SELECT id, floID, txid FROM InputFLO WHERE status=?", ["PENDING"]).then(results => {
|
|
||||||
results.forEach(req => {
|
|
||||||
confirmDepositFLO.checkTx(req.floID, req.txid).then(amount => {
|
|
||||||
confirmDepositFLO.addSellChipsIfLaunchSeller(req.floID, amount).then(txQueries => {
|
|
||||||
txQueries.push(updateBalance.add(req.floID, "FLO", amount));
|
|
||||||
txQueries.push(["UPDATE InputFLO 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 InputFLO SET status=? WHERE id=?", ["REJECTED", req.id])
|
|
||||||
.then(_ => null).catch(error => console.error(error));
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}).catch(error => console.error(error))
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmDepositFLO.checkTx = function(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]))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmDepositFLO.addSellChipsIfLaunchSeller = function(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 withdrawFLO(floID, amount) {
|
function withdrawFLO(floID, amount) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateAddr(floID))
|
||||||
@ -436,33 +366,13 @@ function withdrawFLO(floID, amount) {
|
|||||||
let txQueries = [];
|
let txQueries = [];
|
||||||
txQueries.push(updateBalance.consume(floID, "FLO", amount));
|
txQueries.push(updateBalance.consume(floID, "FLO", amount));
|
||||||
DB.transaction(txQueries).then(result => {
|
DB.transaction(txQueries).then(result => {
|
||||||
blockchain.sendFLO.init(floID, amount);
|
blockchain.sendCoin.init(floID, "FLO", amount);
|
||||||
resolve("Withdrawal request is in process");
|
resolve("Withdrawal request is in process");
|
||||||
}).catch(error => reject(error));
|
}).catch(error => reject(error));
|
||||||
}).catch(error => reject(error));
|
}).catch(error => reject(error));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function retryWithdrawalFLO() {
|
|
||||||
DB.query("SELECT id, floID, amount FROM OutputFLO WHERE status=?", ["PENDING"]).then(results => {
|
|
||||||
results.forEach(req => blockchain.sendFLO.retry(req.floID, req.amount, req.id))
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmWithdrawalFLO() {
|
|
||||||
DB.query("SELECT id, floID, amount, txid FROM OutputFLO WHERE status=?", ["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 OutputFLO 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 depositToken(floID, txid) {
|
function depositToken(floID, txid) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
DB.query("SELECT status FROM InputToken WHERE txid=? AND floID=?", [txid, floID]).then(result => {
|
DB.query("SELECT status FROM InputToken WHERE txid=? AND floID=?", [txid, floID]).then(result => {
|
||||||
@ -483,59 +393,6 @@ function depositToken(floID, txid) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function confirmDepositToken() {
|
|
||||||
DB.query("SELECT id, floID, txid FROM InputToken WHERE status=?", ["PENDING"]).then(results => {
|
|
||||||
results.forEach(req => {
|
|
||||||
confirmDepositToken.checkTx(req.floID, req.txid).then(amounts => {
|
|
||||||
DB.query("SELECT id FROM InputFLO where floID=? AND txid=?", [req.floID, 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 InputFLO(txid, floID, amount, status) VALUES (?, ?, ?, ?)", [req.txid, req.floID, 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))
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmDepositToken.checkTx = function(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 withdrawToken(floID, token, amount) {
|
function withdrawToken(floID, token, amount) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateAddr(floID))
|
||||||
@ -561,24 +418,6 @@ function withdrawToken(floID, token, amount) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
function addTag(floID, tag) {
|
function addTag(floID, tag) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
DB.query("INSERT INTO UserTag (floID, tag) VALUE (?,?)", [floID, tag])
|
DB.query("INSERT INTO UserTag (floID, tag) VALUE (?,?)", [floID, tag])
|
||||||
@ -602,14 +441,6 @@ function removeTag(floID, tag) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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 addDistributor(floID, asset) {
|
function addDistributor(floID, asset) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
DB.query("INSERT INTO Distributors (floID, asset) VALUE (?,?)", [floID, asset])
|
DB.query("INSERT INTO Distributors (floID, asset) VALUE (?,?)", [floID, asset])
|
||||||
@ -675,12 +506,13 @@ function blockchainReCheck() {
|
|||||||
floBlockchainAPI.promisedAPI('api/blocks?limit=1').then(result => {
|
floBlockchainAPI.promisedAPI('api/blocks?limit=1').then(result => {
|
||||||
if (lastSyncBlockHeight < result.blocks[0].height) {
|
if (lastSyncBlockHeight < result.blocks[0].height) {
|
||||||
lastSyncBlockHeight = result.blocks[0].height;
|
lastSyncBlockHeight = result.blocks[0].height;
|
||||||
confirmDepositFLO();
|
background.confirmDepositFLO();
|
||||||
confirmDepositToken();
|
background.confirmDepositToken();
|
||||||
retryWithdrawalFLO();
|
background.retryWithdrawalCoin();
|
||||||
retryWithdrawalToken();
|
background.retryWithdrawalToken();
|
||||||
confirmWithdrawalFLO();
|
background.confirmWithdrawalFLO();
|
||||||
confirmWithdrawalToken();
|
background.confirmWithdrawalBTC();
|
||||||
|
background.confirmWithdrawalToken();
|
||||||
console.debug("Last Block :", lastSyncBlockHeight);
|
console.debug("Last Block :", lastSyncBlockHeight);
|
||||||
}
|
}
|
||||||
}).catch(error => console.error(error));
|
}).catch(error => console.error(error));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user