Updating sell-requirement
- Users can only sell when enough sell-chips (for asset) are available. - sell-chips are obtained by . buying assets . receiving asset from distributor . deposit (FLO only) as launch-seller (maximum of 1 million) - Updated coupling for the requirement - Improved getBestSeller and getBestBuyer: Directly fetch from SQL query - Removed group.js (moved required functions to market.js) - Updated SQL schema
This commit is contained in:
parent
9caf3fc9ec
commit
f9551c856d
104
args/schema.sql
104
args/schema.sql
@ -16,13 +16,12 @@ CREATE TABLE TagList (
|
|||||||
tag VARCHAR(50) NOT NULL,
|
tag VARCHAR(50) NOT NULL,
|
||||||
sellPriority INT,
|
sellPriority INT,
|
||||||
buyPriority INT,
|
buyPriority INT,
|
||||||
api TINYTEXT,
|
|
||||||
PRIMARY KEY(tag)
|
PRIMARY KEY(tag)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE AssetList (
|
CREATE TABLE AssetList (
|
||||||
asset VARCHAR(64) NOT NULL,
|
asset VARCHAR(64) NOT NULL,
|
||||||
initialPrice FLOAT,
|
initialPrice DECIMAL(10, 2),
|
||||||
PRIMARY KEY(asset)
|
PRIMARY KEY(asset)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -42,21 +41,22 @@ CREATE TABLE UserSession (
|
|||||||
PRIMARY KEY(floID)
|
PRIMARY KEY(floID)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE Cash (
|
CREATE TABLE UserBalance (
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
floID CHAR(34) NOT NULL UNIQUE,
|
floID CHAR(34) NOT NULL,
|
||||||
balance DECIMAL(12, 2) DEFAULT 0.00,
|
token VARCHAR(64) NOT NULL,
|
||||||
KEY(id),
|
quantity DECIMAL(10, 2) NOT NULL DEFAULT 0,
|
||||||
PRIMARY KEY(floID)
|
PRIMARY KEY(floID, token),
|
||||||
);
|
KEY(id)
|
||||||
|
)
|
||||||
|
|
||||||
CREATE TABLE Vault (
|
CREATE TABLE SellChips (
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
floID CHAR(34) NOT NULL,
|
floID CHAR(34) NOT NULL,
|
||||||
locktime DATETIME DEFAULT CURRENT_TIMESTAMP,
|
locktime DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
asset VARCHAR(64) NOT NULL,
|
asset VARCHAR(64) NOT NULL,
|
||||||
base DECIMAL(10, 2),
|
base DECIMAL(10, 2) NOT NULL DEFAULT 0,
|
||||||
quantity FLOAT NOT NULL,
|
quantity DECIMAL(10, 2) NOT NULL,
|
||||||
PRIMARY KEY(id),
|
PRIMARY KEY(id),
|
||||||
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
||||||
);
|
);
|
||||||
@ -70,6 +70,15 @@ CREATE TABLE UserTag (
|
|||||||
FOREIGN KEY (tag) REFERENCES TagList(tag)
|
FOREIGN KEY (tag) REFERENCES TagList(tag)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Distributors(
|
||||||
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
floID CHAR(34) NOT NULL,
|
||||||
|
asset VARCHAR(64) NOT NULL,
|
||||||
|
KEY(id),
|
||||||
|
PRIMARY KEY(floID, asset),
|
||||||
|
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
||||||
|
)
|
||||||
|
|
||||||
/* User Requests */
|
/* User Requests */
|
||||||
|
|
||||||
CREATE TABLE RequestLog(
|
CREATE TABLE RequestLog(
|
||||||
@ -87,7 +96,7 @@ CREATE TABLE SellOrder (
|
|||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
floID CHAR(34) NOT NULL,
|
floID CHAR(34) NOT NULL,
|
||||||
asset VARCHAR(64) NOT NULL,
|
asset VARCHAR(64) NOT NULL,
|
||||||
quantity FLOAT NOT NULL,
|
quantity DECIMAL(10, 2) NOT NULL,
|
||||||
minPrice DECIMAL(10, 2) NOT NULL,
|
minPrice DECIMAL(10, 2) NOT NULL,
|
||||||
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
|
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY(id),
|
PRIMARY KEY(id),
|
||||||
@ -98,7 +107,7 @@ CREATE TABLE BuyOrder (
|
|||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
floID CHAR(34) NOT NULL,
|
floID CHAR(34) NOT NULL,
|
||||||
asset VARCHAR(64) NOT NULL,
|
asset VARCHAR(64) NOT NULL,
|
||||||
quantity FLOAT NOT NULL,
|
quantity DECIMAL(10, 2) NOT NULL,
|
||||||
maxPrice DECIMAL(10, 2) NOT NULL,
|
maxPrice DECIMAL(10, 2) NOT NULL,
|
||||||
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
|
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY(id),
|
PRIMARY KEY(id),
|
||||||
@ -109,7 +118,7 @@ CREATE TABLE InputFLO (
|
|||||||
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,
|
||||||
amount FLOAT,
|
amount DECIMAL(10, 2),
|
||||||
status VARCHAR(50) NOT NULL,
|
status VARCHAR(50) NOT NULL,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
||||||
@ -118,7 +127,7 @@ CREATE TABLE OutputFLO (
|
|||||||
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,
|
||||||
amount FLOAT NOT NULL,
|
amount DECIMAL(10, 2) NOT NULL,
|
||||||
status VARCHAR(50) NOT NULL,
|
status VARCHAR(50) NOT NULL,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
||||||
@ -128,7 +137,7 @@ CREATE TABLE InputToken (
|
|||||||
txid VARCHAR(128) NOT NULL,
|
txid VARCHAR(128) NOT NULL,
|
||||||
floID CHAR(34) NOT NULL,
|
floID CHAR(34) NOT NULL,
|
||||||
token VARCHAR(64),
|
token VARCHAR(64),
|
||||||
amount FLOAT,
|
amount DECIMAL(10, 2),
|
||||||
status VARCHAR(50) NOT NULL,
|
status VARCHAR(50) NOT NULL,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
||||||
@ -138,7 +147,7 @@ CREATE TABLE OutputToken (
|
|||||||
txid VARCHAR(128),
|
txid VARCHAR(128),
|
||||||
floID CHAR(34) NOT NULL,
|
floID CHAR(34) NOT NULL,
|
||||||
token VARCHAR(64),
|
token VARCHAR(64),
|
||||||
amount FLOAT NOT NULL,
|
amount DECIMAL(10, 2) NOT NULL,
|
||||||
status VARCHAR(50) NOT NULL,
|
status VARCHAR(50) NOT NULL,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
||||||
@ -148,7 +157,7 @@ CREATE TABLE OutputToken (
|
|||||||
CREATE TABLE PriceHistory (
|
CREATE TABLE PriceHistory (
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
asset VARCHAR(64) NOT NULL,
|
asset VARCHAR(64) NOT NULL,
|
||||||
rate FLOAT NOT NULL,
|
rate DECIMAL(10, 2) NOT NULL,
|
||||||
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY(id),
|
PRIMARY KEY(id),
|
||||||
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
||||||
@ -159,7 +168,7 @@ CREATE TABLE TransferTransactions (
|
|||||||
sender CHAR(34) NOT NULL,
|
sender CHAR(34) NOT NULL,
|
||||||
receiver TEXT NOT NULL,
|
receiver TEXT NOT NULL,
|
||||||
token VARCHAR(64) NOT NULL,
|
token VARCHAR(64) NOT NULL,
|
||||||
totalAmount FLOAT NOT NULL,
|
totalAmount DECIMAL(10, 2) NOT NULL,
|
||||||
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
txid VARCHAR(66) NOT NULL,
|
txid VARCHAR(66) NOT NULL,
|
||||||
KEY(id),
|
KEY(id),
|
||||||
@ -171,7 +180,7 @@ CREATE TABLE TradeTransactions (
|
|||||||
seller CHAR(34) NOT NULL,
|
seller CHAR(34) NOT NULL,
|
||||||
buyer CHAR(34) NOT NULL,
|
buyer CHAR(34) NOT NULL,
|
||||||
asset VARCHAR(64) NOT NULL,
|
asset VARCHAR(64) NOT NULL,
|
||||||
quantity FLOAT NOT NULL,
|
quantity DECIMAL(10, 2) NOT NULL,
|
||||||
unitValue DECIMAL(10, 2) NOT NULL,
|
unitValue DECIMAL(10, 2) NOT NULL,
|
||||||
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
txid VARCHAR(66) NOT NULL,
|
txid VARCHAR(66) NOT NULL,
|
||||||
@ -183,20 +192,20 @@ CREATE TABLE TradeTransactions (
|
|||||||
CREATE TABLE AuditTrade(
|
CREATE TABLE AuditTrade(
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
unit_price FLOAT NOT NULL,
|
unit_price DECIMAL(10, 2) NOT NULL,
|
||||||
quantity FLOAT NOT NULL,
|
quantity DECIMAL(10, 2) NOT NULL,
|
||||||
total_cost FLOAT NOT NULL,
|
total_cost DECIMAL(10, 2) NOT NULL,
|
||||||
asset VARCHAR(64) NOT NULL,
|
asset VARCHAR(64) NOT NULL,
|
||||||
sellerID CHAR(34) NOT NULL,
|
sellerID CHAR(34) NOT NULL,
|
||||||
seller_old_asset FLOAT NOT NULL,
|
seller_old_asset DECIMAL(10, 2) NOT NULL,
|
||||||
seller_new_asset FLOAT NOT NULL,
|
seller_new_asset DECIMAL(10, 2) NOT NULL,
|
||||||
seller_old_cash FLOAT NOT NULL,
|
seller_old_cash DECIMAL(10, 2) NOT NULL,
|
||||||
seller_new_cash FLOAT NOT NULL,
|
seller_new_cash DECIMAL(10, 2) NOT NULL,
|
||||||
buyerID CHAR(34) NOT NULL,
|
buyerID CHAR(34) NOT NULL,
|
||||||
buyer_old_asset FLOAT NOT NULL,
|
buyer_old_asset DECIMAL(10, 2) NOT NULL,
|
||||||
buyer_new_asset FLOAT NOT NULL,
|
buyer_new_asset DECIMAL(10, 2) NOT NULL,
|
||||||
buyer_old_cash FLOAT NOT NULL,
|
buyer_old_cash DECIMAL(10, 2) NOT NULL,
|
||||||
buyer_new_cash FLOAT NOT NULL,
|
buyer_new_cash DECIMAL(10, 2) NOT NULL,
|
||||||
PRIMARY KEY(id),
|
PRIMARY KEY(id),
|
||||||
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
FOREIGN KEY (asset) REFERENCES AssetList(asset)
|
||||||
);
|
);
|
||||||
@ -204,7 +213,7 @@ CREATE TABLE AuditTrade(
|
|||||||
/* Backup Feature (Tables & Triggers) */
|
/* Backup Feature (Tables & Triggers) */
|
||||||
|
|
||||||
CREATE TABLE _backup (
|
CREATE TABLE _backup (
|
||||||
t_name VARCHAR(20),
|
t_name TINYTEXT,
|
||||||
id INT,
|
id INT,
|
||||||
mode BOOLEAN DEFAULT TRUE,
|
mode BOOLEAN DEFAULT TRUE,
|
||||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
@ -240,19 +249,19 @@ FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserSession', NEW.id) ON
|
|||||||
CREATE TRIGGER UserSession_D AFTER DELETE ON UserSession
|
CREATE TRIGGER UserSession_D AFTER DELETE ON UserSession
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserSession', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserSession', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
||||||
|
|
||||||
CREATE TRIGGER Cash_I AFTER INSERT ON Cash
|
CREATE TRIGGER UserBalance_I AFTER INSERT ON UserBalance
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserBalance', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER Cash_U AFTER UPDATE ON Cash
|
CREATE TRIGGER UserBalance_U AFTER UPDATE ON UserBalance
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserBalance', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER Cash_D AFTER DELETE ON Cash
|
CREATE TRIGGER UserBalance_D AFTER DELETE ON UserBalance
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserBalance', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
||||||
|
|
||||||
CREATE TRIGGER Vault_I AFTER INSERT ON Vault
|
CREATE TRIGGER SellChips_I AFTER INSERT ON SellChips
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Vault', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('SellChips', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER Vault_U AFTER UPDATE ON Vault
|
CREATE TRIGGER SellChips_U AFTER UPDATE ON SellChips
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Vault', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('SellChips', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER Vault_D AFTER DELETE ON Vault
|
CREATE TRIGGER SellChips_D AFTER DELETE ON SellChips
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Vault', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('SellChips', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
||||||
|
|
||||||
CREATE TRIGGER SellOrder_I AFTER INSERT ON SellOrder
|
CREATE TRIGGER SellOrder_I AFTER INSERT ON SellOrder
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('SellOrder', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('SellOrder', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
@ -303,6 +312,13 @@ FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserTag', NEW.id) ON DUPL
|
|||||||
CREATE TRIGGER UserTag_D AFTER DELETE ON UserTag
|
CREATE TRIGGER UserTag_D AFTER DELETE ON UserTag
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserTag', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserTag', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
||||||
|
|
||||||
|
CREATE TRIGGER Distributors_I AFTER INSERT ON Distributors
|
||||||
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Distributors', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
|
CREATE TRIGGER Distributors_U AFTER UPDATE ON Distributors
|
||||||
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Distributors', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
|
CREATE TRIGGER Distributors_D AFTER DELETE ON Distributors
|
||||||
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Distributors', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
|
||||||
|
|
||||||
CREATE TRIGGER PriceHistory_I AFTER INSERT ON PriceHistory
|
CREATE TRIGGER PriceHistory_I AFTER INSERT ON PriceHistory
|
||||||
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('PriceHistory', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('PriceHistory', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
|
||||||
CREATE TRIGGER PriceHistory_U AFTER UPDATE ON PriceHistory
|
CREATE TRIGGER PriceHistory_U AFTER UPDATE ON PriceHistory
|
||||||
|
|||||||
@ -9,7 +9,7 @@ module.exports = {
|
|||||||
INVALID_SERVER_MSG: "INCORRECT_SERVER_ERROR" //Should be reflected in public backend script
|
INVALID_SERVER_MSG: "INCORRECT_SERVER_ERROR" //Should be reflected in public backend script
|
||||||
},
|
},
|
||||||
market: {
|
market: {
|
||||||
MINIMUM_BUY_REQUIREMENT: 0,
|
MAXIMUM_LAUNCH_SELL_CHIPS: 1000000,
|
||||||
TRADE_HASH_PREFIX: "z1",
|
TRADE_HASH_PREFIX: "z1",
|
||||||
TRANSFER_HASH_PREFIX: "z0"
|
TRANSFER_HASH_PREFIX: "z0"
|
||||||
},
|
},
|
||||||
|
|||||||
187
src/coupling.js
187
src/coupling.js
@ -1,6 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const group = require("./group");
|
|
||||||
const price = require("./price");
|
const price = require("./price");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -9,42 +8,84 @@ const {
|
|||||||
|
|
||||||
var DB; //container for database
|
var DB; //container for database
|
||||||
|
|
||||||
|
const updateBalance = {};
|
||||||
|
updateBalance.consume = (floID, token, amount) => ["UPDATE UserBalance SET quantity=quantity-? WHERE floID=? AND token=?", [amount, floID, token]];
|
||||||
|
updateBalance.add = (floID, token, amount) => ["INSERT INTO UserBalance (floID, token, quantity) VALUE (?, ?, ?) ON DUPLICATE KEY UPDATE quantity=quantity+?", [floID, token, amount, amount]];
|
||||||
|
|
||||||
function startCouplingForAsset(asset) {
|
function startCouplingForAsset(asset) {
|
||||||
price.getRates(asset).then(cur_rate => {
|
price.getRates(asset).then(cur_rate => {
|
||||||
cur_rate = cur_rate.toFixed(8);
|
cur_rate = cur_rate.toFixed(8);
|
||||||
group.getBestPairs(asset, cur_rate)
|
processCoupling(asset, cur_rate);
|
||||||
.then(bestPairQueue => processCoupling(bestPairQueue))
|
|
||||||
.catch(error => console.error("initiateCoupling", error))
|
|
||||||
}).catch(error => console.error(error));
|
}).catch(error => console.error(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
function processCoupling(bestPairQueue) {
|
function getBestPair(asset, cur_rate) {
|
||||||
bestPairQueue.get().then(pair_result => {
|
return new Promise((resolve, reject) => {
|
||||||
let buyer_best = pair_result.buyOrder,
|
Promise.allSettled([getBestBuyer(asset, cur_rate), getBestSeller(asset, cur_rate)]).then(results => {
|
||||||
seller_best = pair_result.sellOrder;
|
if (results[0].status === "fulfilled" && results[1].status === "fulfilled")
|
||||||
//console.debug("Sell:", seller_best);
|
resolve({
|
||||||
//console.debug("Buy:", buyer_best);
|
buy: results[0].value,
|
||||||
spendAsset(bestPairQueue.asset, buyer_best, seller_best, pair_result.null_base).then(spent => {
|
sell: results[1].value,
|
||||||
if (!spent.quantity) {
|
})
|
||||||
//Happens when there are only Null-base assets
|
else
|
||||||
bestPairQueue.next(spent.quantity, spent.incomplete);
|
reject({
|
||||||
processCoupling(bestPairQueue);
|
buy: results[0].reason,
|
||||||
return;
|
sell: results[1].reason
|
||||||
}
|
})
|
||||||
let txQueries = spent.txQueries;
|
}).catch(error => reject(error))
|
||||||
processOrders(seller_best, buyer_best, txQueries, spent.quantity, spent.incomplete && pair_result.null_base);
|
})
|
||||||
updateBalance(seller_best, buyer_best, txQueries, bestPairQueue.asset, bestPairQueue.cur_rate, spent.quantity);
|
}
|
||||||
//begin audit
|
|
||||||
beginAudit(seller_best.floID, buyer_best.floID, bestPairQueue.asset, bestPairQueue.cur_rate, spent.quantity).then(audit => {
|
const getBestSeller = (asset, cur_rate) => new Promise((resolve, reject) => {
|
||||||
//process txn query in SQL
|
DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity, SellChips.id AS chip_id, SellChips.quantity AS chip_quantity FROM SellOrder" +
|
||||||
DB.transaction(txQueries).then(_ => {
|
" INNER JOIN UserBalance ON UserBalance.floID = SellOrder.floID AND UserBalance.token = SellOrder.asset" +
|
||||||
bestPairQueue.next(spent.quantity, spent.incomplete);
|
" INNER JOIN SellChips ON SellChips.floID = SellOrder.floID AND SellChips.asset = SellOrder.asset AND SellChips.base <= ?" +
|
||||||
console.log(`Transaction was successful! BuyOrder:${buyer_best.id}| SellOrder:${seller_best.id}`);
|
" LEFT JOIN UserTag ON UserTag.floID = SellOrder.floID" +
|
||||||
audit.end();
|
" LEFT JOIN TagList ON TagList.tag = UserTag.tag" +
|
||||||
price.updateLastTime();
|
" WHERE UserBalance.quantity >= SellOrder.quantity AND SellOrder.asset = ? AND SellOrder.minPrice <= ?" +
|
||||||
//Since a tx was successful, match again
|
" ORDER BY TagList.sellPriority DESC, SellChips.locktime ASC, SellOrder.time_placed ASC" +
|
||||||
processCoupling(bestPairQueue);
|
" LIMIT 1", [cur_rate, asset, cur_rate]
|
||||||
}).catch(error => console.error(error));
|
).then(result => {
|
||||||
|
if (result.length)
|
||||||
|
resolve(result[0]);
|
||||||
|
else
|
||||||
|
reject(null);
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
});
|
||||||
|
|
||||||
|
const getBestBuyer = (asset, cur_rate) => new Promise((resolve, reject) => {
|
||||||
|
DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" +
|
||||||
|
" INNER JOIN UserBalance ON UserBalance.floID = BuyOrder.floID AND UserBalance.token = ?" +
|
||||||
|
" LEFT JOIN UserTag ON UserTag.floID = BuyOrder.floID" +
|
||||||
|
" LEFT JOIN TagList ON TagList.tag = UserTag.tag" +
|
||||||
|
" WHERE UserBalance.quantity >= BuyOrder.maxPrice * BuyOrder.quantity AND BuyOrder.asset = ? AND BuyOrder.maxPrice >= ?" +
|
||||||
|
" ORDER BY TagList.buyPriority DESC, BuyOrder.time_placed ASC" +
|
||||||
|
" LIMIT 1", [floGlobals.currency, asset, cur_rate]
|
||||||
|
).then(result => {
|
||||||
|
if (result.length)
|
||||||
|
resolve(result[0]);
|
||||||
|
else
|
||||||
|
reject(null);
|
||||||
|
}).catch(error => reject(error))
|
||||||
|
});
|
||||||
|
|
||||||
|
function processCoupling(asset, cur_rate) {
|
||||||
|
getBestPair(asset, cur_rate).then(best => {
|
||||||
|
//console.debug("Sell:", best.sell);
|
||||||
|
//console.debug("Buy:", best.buy);
|
||||||
|
let quantity = Math.min(best.buy.quantity, best.sell.quantity, best.sell.chip_quantity);
|
||||||
|
let txQueries = [];
|
||||||
|
processOrders(best.sell, best.buy, txQueries, quantity);
|
||||||
|
updateBalance(best.sell, best.buy, txQueries, asset, cur_rate, quantity);
|
||||||
|
//begin audit
|
||||||
|
beginAudit(best.sell.floID, best.buy.floID, asset, cur_rate, quantity).then(audit => {
|
||||||
|
//process txn query in SQL
|
||||||
|
DB.transaction(txQueries).then(_ => {
|
||||||
|
console.log(`Transaction was successful! BuyOrder:${best.buy.id}| SellOrder:${best.sell.id}`);
|
||||||
|
audit.end();
|
||||||
|
price.updateLastTime();
|
||||||
|
//Since a tx was successful, match again
|
||||||
|
processCoupling(asset, cur_rate);
|
||||||
}).catch(error => console.error(error));
|
}).catch(error => console.error(error));
|
||||||
}).catch(error => console.error(error));
|
}).catch(error => console.error(error));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
@ -55,7 +96,7 @@ function processCoupling(bestPairQueue) {
|
|||||||
console.error(error.buy);
|
console.error(error.buy);
|
||||||
noBuy = null;
|
noBuy = null;
|
||||||
} else {
|
} else {
|
||||||
console.log("No valid buyOrders for Asset:", bestPairQueue.asset);
|
console.log("No valid buyOrders for Asset:", asset);
|
||||||
noBuy = true;
|
noBuy = true;
|
||||||
}
|
}
|
||||||
if (error.sell === undefined)
|
if (error.sell === undefined)
|
||||||
@ -64,37 +105,14 @@ function processCoupling(bestPairQueue) {
|
|||||||
console.error(error.sell);
|
console.error(error.sell);
|
||||||
noSell = null;
|
noSell = null;
|
||||||
} else {
|
} else {
|
||||||
console.log("No valid sellOrders for Asset:", bestPairQueue.asset);
|
console.log("No valid sellOrders for Asset:", asset);
|
||||||
noSell = true;
|
noSell = true;
|
||||||
}
|
}
|
||||||
price.noOrder(bestPairQueue.asset, noBuy, noSell);
|
price.noOrder(asset, noBuy, noSell);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function spendAsset(asset, buyOrder, sellOrder, null_base) {
|
function processOrders(seller_best, buyer_best, txQueries, quantity) {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query('SELECT id, quantity FROM Vault WHERE floID=? AND asset=? AND base IS ' +
|
|
||||||
(null_base ? "NULL ORDER BY locktime" : "NOT NULL ORDER BY base"), [sellOrder.floID, asset]).then(result => {
|
|
||||||
let rem = Math.min(buyOrder.quantity, sellOrder.quantity),
|
|
||||||
txQueries = [];
|
|
||||||
for (let i = 0; i < result.length && rem > 0; i++)
|
|
||||||
if (rem < result[i].quantity) {
|
|
||||||
txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]);
|
|
||||||
rem = 0;
|
|
||||||
} else {
|
|
||||||
txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]);
|
|
||||||
rem -= result[i].quantity;
|
|
||||||
}
|
|
||||||
resolve({
|
|
||||||
quantity: Math.min(buyOrder.quantity, sellOrder.quantity) - rem,
|
|
||||||
txQueries,
|
|
||||||
incomplete: rem > 0
|
|
||||||
});
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function processOrders(seller_best, buyer_best, txQueries, quantity, clear_sell) {
|
|
||||||
if (quantity > buyer_best.quantity || quantity > seller_best.quantity)
|
if (quantity > buyer_best.quantity || quantity > seller_best.quantity)
|
||||||
throw Error("Tx quantity cannot be more than order quantity");
|
throw Error("Tx quantity cannot be more than order quantity");
|
||||||
//Process Buy Order
|
//Process Buy Order
|
||||||
@ -103,19 +121,26 @@ function processOrders(seller_best, buyer_best, txQueries, quantity, clear_sell)
|
|||||||
else
|
else
|
||||||
txQueries.push(["UPDATE BuyOrder SET quantity=quantity-? WHERE id=?", [quantity, buyer_best.id]]);
|
txQueries.push(["UPDATE BuyOrder SET quantity=quantity-? WHERE id=?", [quantity, buyer_best.id]]);
|
||||||
//Process Sell Order
|
//Process Sell Order
|
||||||
if (quantity == seller_best.quantity || clear_sell) //clear_sell must be true iff an order is placed without enough Asset
|
if (quantity == seller_best.quantity)
|
||||||
txQueries.push(["DELETE FROM SellOrder WHERE id=?", [seller_best.id]]);
|
txQueries.push(["DELETE FROM SellOrder WHERE id=?", [seller_best.id]]);
|
||||||
else
|
else
|
||||||
txQueries.push(["UPDATE SellOrder SET quantity=quantity-? WHERE id=?", [quantity, seller_best.id]]);
|
txQueries.push(["UPDATE SellOrder SET quantity=quantity-? WHERE id=?", [quantity, seller_best.id]]);
|
||||||
|
//Process Sell Chip
|
||||||
|
if (quantity == seller_best.chip_quantity)
|
||||||
|
txQueries.push(["DELETE FROM SellChips WHERE id=?", [seller_best.chip_id]]);
|
||||||
|
else
|
||||||
|
txQueries.push(["UPDATE SellChips SET quantity=quantity-? WHERE id=?", [quantity, seller_best.chip_id]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateBalance(seller_best, buyer_best, txQueries, asset, cur_price, quantity) {
|
function updateBalance(seller_best, buyer_best, txQueries, asset, cur_price, quantity) {
|
||||||
//Update cash balance for seller and buyer
|
//Update cash/asset balance for seller and buyer
|
||||||
let totalAmount = cur_price * quantity;
|
let totalAmount = cur_price * quantity;
|
||||||
txQueries.push(["INSERT INTO Cash (floID, balance) VALUE (?, ?) ON DUPLICATE KEY UPDATE balance=balance+?", [seller_best.floID, totalAmount, totalAmount]]);
|
txQueries.push(updateBalance.add(seller_best.floID, floGlobals.currency, totalAmount));
|
||||||
txQueries.push(["UPDATE Cash SET balance=balance-? WHERE floID=?", [totalAmount, buyer_best.floID]]);
|
txQueries.push(updateBalance.consume(buyer_best.floID, floGlobals.currency, totalAmount));
|
||||||
//Add coins to Buyer
|
txQueries.push(updateBalance.add(seller_best.floID, asset, totalAmount));
|
||||||
txQueries.push(["INSERT INTO Vault(floID, asset, base, quantity) VALUES (?, ?, ?, ?)", [buyer_best.floID, asset, cur_price, quantity]])
|
txQueries.push(updateBalance.consume(buyer_best.floID, asset, totalAmount));
|
||||||
|
//Add SellChips to Buyer
|
||||||
|
txQueries.push(["INSERT INTO SellChips(floID, asset, base, quantity) VALUES (?, ?, ?, ?)", [buyer_best.floID, asset, cur_price, quantity]])
|
||||||
//Record transaction
|
//Record transaction
|
||||||
let time = Date.now();
|
let time = Date.now();
|
||||||
let hash = TRADE_HASH_PREFIX + Crypto.SHA256(JSON.stringify({
|
let hash = TRADE_HASH_PREFIX + Crypto.SHA256(JSON.stringify({
|
||||||
@ -156,33 +181,33 @@ function endAudit(sellerID, buyerID, asset, old_bal, unit_price, quantity) {
|
|||||||
function auditBalance(sellerID, buyerID, asset) {
|
function auditBalance(sellerID, buyerID, asset) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let balance = {
|
let balance = {
|
||||||
[sellerID]: {},
|
[sellerID]: {
|
||||||
[buyerID]: {}
|
cash: 0,
|
||||||
|
asset: 0
|
||||||
|
},
|
||||||
|
[buyerID]: {
|
||||||
|
cash: 0,
|
||||||
|
asset: 0
|
||||||
|
}
|
||||||
};
|
};
|
||||||
DB.query("SELECT floID, balance FROM Cash WHERE floID IN (?, ?)", [sellerID, buyerID]).then(result => {
|
DB.query("SELECT floID, quantity, token FROM UserBalance WHERE floID IN (?, ?) AND token IN (?, ?)", [sellerID, buyerID, floGlobals.currency, asset]).then(result => {
|
||||||
for (let i in result)
|
for (let i in result) {
|
||||||
balance[result[i].floID].cash = result[i].balance;
|
if (result[i].token === floGlobals.currency)
|
||||||
DB.query("SELECT floID, SUM(quantity) as asset_balance FROM Vault WHERE asset=? AND floID IN (?, ?) GROUP BY floID", [asset, sellerID, buyerID]).then(result => {
|
balance[result[i].floID].cash = result[i].quantity;
|
||||||
for (let i in result)
|
else if (result[i].token === asset)
|
||||||
balance[result[i].floID].asset = result[i].asset_balance;
|
balance[result[i].floID].asset = result[i].quantity;
|
||||||
//Set them as 0 if undefined or null
|
}
|
||||||
balance[sellerID].cash = balance[sellerID].cash || 0;
|
resolve(balance);
|
||||||
balance[sellerID].asset = balance[sellerID].asset || 0;
|
|
||||||
balance[buyerID].cash = balance[buyerID].cash || 0;
|
|
||||||
balance[buyerID].asset = balance[buyerID].asset || 0;
|
|
||||||
resolve(balance);
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
initiate: startCouplingForAsset,
|
initiate: startCouplingForAsset,
|
||||||
group: group,
|
updateBalance,
|
||||||
price,
|
price,
|
||||||
set DB(db) {
|
set DB(db) {
|
||||||
DB = db;
|
DB = db;
|
||||||
group.DB = db;
|
|
||||||
price.DB = db;
|
price.DB = db;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
419
src/group.js
419
src/group.js
@ -1,419 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
var DB; //container for database
|
|
||||||
|
|
||||||
function addTag(floID, tag) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("INSERT INTO UserTag (floID, tag) VALUE (?,?)", [floID, tag])
|
|
||||||
.then(result => resolve(`Added ${floID} to ${tag}`))
|
|
||||||
.catch(error => {
|
|
||||||
if (error.code === "ER_DUP_ENTRY")
|
|
||||||
reject(INVALID(`${floID} already in ${tag}`));
|
|
||||||
else if (error.code === "ER_NO_REFERENCED_ROW")
|
|
||||||
reject(INVALID(`Invalid Tag`));
|
|
||||||
else
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeTag(floID, tag) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("DELETE FROM UserTag WHERE floID=? AND tag=?", [floID, tag])
|
|
||||||
.then(result => resolve(`Removed ${floID} from ${tag}`))
|
|
||||||
.catch(error => reject(error));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function addDistributor(floID, asset) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("INSERT INTO Distributors (floID, asset) VALUE (?,?)", [floID, asset])
|
|
||||||
.then(result => resolve(`Added ${asset} distributor: ${floID}`))
|
|
||||||
.catch(error => {
|
|
||||||
if (error.code === "ER_DUP_ENTRY")
|
|
||||||
reject(INVALID(`${floID} is already ${asset} disributor`));
|
|
||||||
else if (error.code === "ER_NO_REFERENCED_ROW")
|
|
||||||
reject(INVALID(`Invalid Asset`));
|
|
||||||
else
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeDistributor(floID, asset) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("DELETE FROM Distributors WHERE floID=? AND tag=?", [floID, asset])
|
|
||||||
.then(result => resolve(`Removed ${asset} distributor: ${floID}`))
|
|
||||||
.catch(error => reject(error));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkDistributor(floID, asset) {
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
DB.query("SELECT id FROM Distributors WHERE floID=? AND asset=?", [floID, asset])
|
|
||||||
.then(result => resolve(result.length ? true : false))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBestPairs(asset, cur_rate) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("SELECT tag, sellPriority, buyPriority FROM TagList").then(result => {
|
|
||||||
//Sorted in Ascending (ie, stack; pop for highest)
|
|
||||||
let tags_buy = result.sort((a, b) => a.buyPriority > b.buyPriority ? 1 : -1).map(r => r.tag);
|
|
||||||
let tags_sell = result.sort((a, b) => a.sellPriority > b.sellPriority ? 1 : -1).map(r => r.tag);
|
|
||||||
resolve(new bestPair(asset, cur_rate, tags_buy, tags_sell));
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const bestPair = function(asset, cur_rate, tags_buy, tags_sell) {
|
|
||||||
|
|
||||||
Object.defineProperty(this, 'asset', {
|
|
||||||
get: () => asset
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.defineProperty(this, 'cur_rate', {
|
|
||||||
get: () => cur_rate,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.get = () => new Promise((resolve, reject) => {
|
|
||||||
Promise.allSettled([getBuyOrder(), getSellOrder()]).then(results => {
|
|
||||||
if (results[0].status === "fulfilled" && results[1].status === "fulfilled")
|
|
||||||
resolve({
|
|
||||||
buyOrder: results[0].value,
|
|
||||||
sellOrder: results[1].value,
|
|
||||||
null_base: getSellOrder.cache.mode_null
|
|
||||||
})
|
|
||||||
else
|
|
||||||
reject({
|
|
||||||
buy: results[0].reason,
|
|
||||||
sell: results[1].reason
|
|
||||||
})
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
});
|
|
||||||
|
|
||||||
this.next = (tx_quantity, incomplete_sell) => {
|
|
||||||
let buy = getBuyOrder.cache,
|
|
||||||
sell = getSellOrder.cache;
|
|
||||||
if (buy.cur_order && sell.cur_order) {
|
|
||||||
//buy order
|
|
||||||
if (tx_quantity < buy.cur_order.quantity)
|
|
||||||
buy.cur_order.quantity -= tx_quantity;
|
|
||||||
else if (tx_quantity == buy.cur_order.quantity)
|
|
||||||
buy.cur_order = null;
|
|
||||||
else
|
|
||||||
throw Error("Tx quantity cannot be more than order quantity");
|
|
||||||
//sell order
|
|
||||||
if (tx_quantity < sell.cur_order.quantity) {
|
|
||||||
sell.cur_order.quantity -= tx_quantity;
|
|
||||||
if (incomplete_sell) {
|
|
||||||
if (!sell.mode_null)
|
|
||||||
sell.null_queue.push(sell.cur_order);
|
|
||||||
sell.cur_order = null;
|
|
||||||
}
|
|
||||||
} else if (tx_quantity == sell.cur_order.quantity)
|
|
||||||
sell.cur_order = null;
|
|
||||||
else
|
|
||||||
throw Error("Tx quantity cannot be more than order quantity");
|
|
||||||
} else
|
|
||||||
throw Error("No current order found");
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSellOrder = () => new Promise((resolve, reject) => {
|
|
||||||
let cache = getSellOrder.cache;
|
|
||||||
if (cache.cur_order) { //If cache already has a pending order
|
|
||||||
verifySellOrder(cache.cur_order, asset, cur_rate, cache.mode_null).then(result => {
|
|
||||||
cache.cur_order = result;
|
|
||||||
resolve(result);
|
|
||||||
}).catch(error => {
|
|
||||||
if (error !== false)
|
|
||||||
return reject(error);
|
|
||||||
//Order not valid (minimum gain)
|
|
||||||
cache.cur_order = null;
|
|
||||||
getSellOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
})
|
|
||||||
} else if (cache.orders && cache.orders.length) { //If cache already has orders in priority
|
|
||||||
getTopValidSellOrder(cache.orders, asset, cur_rate, cache.mode_null).then(result => {
|
|
||||||
cache.cur_order = result;
|
|
||||||
resolve(result);
|
|
||||||
}).catch(error => {
|
|
||||||
if (error !== false)
|
|
||||||
return reject(error);
|
|
||||||
//No valid order found in current tag
|
|
||||||
cache.orders = null;
|
|
||||||
getSellOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
})
|
|
||||||
} else if (cache.tags.length) { //If cache has remaining tags
|
|
||||||
cache.cur_tag = cache.tags.pop();
|
|
||||||
getSellOrdersInTag(cache.cur_tag, asset, cur_rate).then(orders => {
|
|
||||||
cache.orders = orders;
|
|
||||||
getSellOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
} else if (!cache.end) { //Un-tagged floID's orders (do only once)
|
|
||||||
getUntaggedSellOrders(asset, cur_rate).then(orders => {
|
|
||||||
cache.orders = orders;
|
|
||||||
cache.cur_tag = null;
|
|
||||||
cache.end = true;
|
|
||||||
getSellOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
} else if (!cache.mode_null) { //Lowest priority Assets (Brought from other sources)
|
|
||||||
cache.orders = cache.null_queue.reverse(); //Reverse it so that we can pop the highest priority
|
|
||||||
cache.mode_null = true;
|
|
||||||
cache.null_queue = null;
|
|
||||||
getSellOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
} else
|
|
||||||
reject(false);
|
|
||||||
});
|
|
||||||
getSellOrder.cache = {
|
|
||||||
tags: tags_sell,
|
|
||||||
null_queue: [],
|
|
||||||
mode_null: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const getBuyOrder = () => new Promise((resolve, reject) => {
|
|
||||||
let cache = getBuyOrder.cache;
|
|
||||||
if (cache.cur_order) { //If cache already has a pending order
|
|
||||||
verifyBuyOrder(cache.cur_order, cur_rate).then(result => {
|
|
||||||
cache.cur_order = result;
|
|
||||||
resolve(result);
|
|
||||||
}).catch(error => {
|
|
||||||
if (error !== false)
|
|
||||||
return reject(error);
|
|
||||||
//Order not valid (cash not available)
|
|
||||||
cache.cur_order = null;
|
|
||||||
getBuyOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
})
|
|
||||||
} else if (cache.orders && cache.orders.length) { //If cache already has orders in priority
|
|
||||||
getTopValidBuyOrder(cache.orders, cur_rate).then(result => {
|
|
||||||
cache.cur_order = result;
|
|
||||||
resolve(result);
|
|
||||||
}).catch(error => {
|
|
||||||
if (error !== false)
|
|
||||||
return reject(error);
|
|
||||||
//No valid order found in current tag
|
|
||||||
cache.orders = null;
|
|
||||||
getBuyOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
})
|
|
||||||
} else if (cache.tags.length) { //If cache has remaining tags
|
|
||||||
cache.cur_tag = cache.tags.pop();
|
|
||||||
getBuyOrdersInTag(cache.cur_tag, asset, cur_rate).then(orders => {
|
|
||||||
cache.orders = orders;
|
|
||||||
getBuyOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
} else if (!cache.end) { //Un-tagged floID's orders (do only once)
|
|
||||||
getUntaggedBuyOrders(asset, cur_rate).then(orders => {
|
|
||||||
cache.orders = orders;
|
|
||||||
cache.cur_tag = null;
|
|
||||||
cache.end = true;
|
|
||||||
getBuyOrder()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
} else
|
|
||||||
reject(false);
|
|
||||||
});
|
|
||||||
getBuyOrder.cache = {
|
|
||||||
tags: tags_buy
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUntaggedSellOrders(asset, cur_price) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity FROM SellOrder" +
|
|
||||||
" LEFT JOIN UserTag ON UserTag.floID = SellOrder.floID" +
|
|
||||||
" WHERE UserTag.floID IS NULL AND SellOrder.asset = ? AND SellOrder.minPrice <=?" +
|
|
||||||
" ORDER BY SellOrder.time_placed", [asset, cur_price])
|
|
||||||
.then(orders => resolve(orders))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUntaggedBuyOrders(asset, cur_price) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" +
|
|
||||||
" LEFT JOIN UserTag ON UserTag.floID = BuyOrder.floID" +
|
|
||||||
" WHERE UserTag.floID IS NULL AND BuyOrder.asset = ? AND BuyOrder.maxPrice >=? " +
|
|
||||||
" ORDER BY BuyOrder.time_placed", [asset, cur_price])
|
|
||||||
.then(orders => resolve(orders))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSellOrdersInTag(tag, asset, cur_price) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity FROM SellOrder" +
|
|
||||||
" INNER JOIN UserTag ON UserTag.floID = SellOrder.floID" +
|
|
||||||
" WHERE UserTag.tag = ? AND SellOrder.asset = ? AND SellOrder.minPrice <=?" +
|
|
||||||
" ORDER BY SellOrder.time_placed", [tag, asset, cur_price]).then(orders => {
|
|
||||||
if (orders.length <= 1) // No (or) Only-one order, hence priority sort not required.
|
|
||||||
resolve(orders);
|
|
||||||
else
|
|
||||||
getPointsFromAPI(tag, orders.map(o => o.floID)).then(points => {
|
|
||||||
let orders_sorted = orders.map(o => [o, points[o.floID]])
|
|
||||||
.sort((a, b) => a[1] > b[1] ? -1 : a[1] < b[1] ? 1 : 0) //sort by points (ascending)
|
|
||||||
.map(x => x[0]);
|
|
||||||
resolve(orders_sorted);
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBuyOrdersInTag(tag, asset, cur_price) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" +
|
|
||||||
" INNER JOIN UserTag ON UserTag.floID = BuyOrder.floID" +
|
|
||||||
" WHERE UserTag.tag = ? AND BuyOrder.asset = ? AND BuyOrder.maxPrice >=?" +
|
|
||||||
" ORDER BY BuyOrder.time_placed", [tag, asset, cur_price]).then(orders => {
|
|
||||||
if (orders.length <= 1) // No (or) Only-one order, hence priority sort not required.
|
|
||||||
resolve(orders);
|
|
||||||
else
|
|
||||||
getPointsFromAPI(tag, orders.map(o => o.floID)).then(points => {
|
|
||||||
let orders_sorted = orders.map(o => [o, points[o.floID]])
|
|
||||||
.sort((a, b) => a[1] > b[1] ? -1 : a[1] < b[1] ? 1 : 0) //sort by points (ascending)
|
|
||||||
.map(x => x[0]);
|
|
||||||
resolve(orders_sorted);
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPointsFromAPI(tag, floIDs) {
|
|
||||||
floIDs = Array.from(new Set(floIDs));
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("SELECT api FROM TagList WHERE tag=?", [tag]).then(result => {
|
|
||||||
let api = result[0].api;
|
|
||||||
Promise.allSettled(floIDs.map(id => fetch_api(api, id))).then(result => {
|
|
||||||
let points = {};
|
|
||||||
for (let i in result)
|
|
||||||
points[floIDs[i]] = result[i].status === "fulfilled" ? result[i].value : 0;
|
|
||||||
resolve(points);
|
|
||||||
})
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function fetch_api(api, id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
//TODO: fetch data from API
|
|
||||||
let url = api.replace('<flo-id>', id);
|
|
||||||
global.fetch(url).then(response => {
|
|
||||||
if (response.ok)
|
|
||||||
response.text()
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error))
|
|
||||||
else
|
|
||||||
reject(response);
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTopValidSellOrder(orders, asset, cur_price, mode_null) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!orders.length)
|
|
||||||
return reject(false)
|
|
||||||
verifySellOrder(orders.pop(), asset, cur_price, mode_null) //pop: as the orders are sorted in ascending (highest point should be checked 1st)
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => {
|
|
||||||
if (error !== false)
|
|
||||||
return reject(error);
|
|
||||||
getTopValidSellOrder(orders, asset, cur_price, mode_null)
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifySellOrder(sellOrder, asset, cur_price, mode_null) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!mode_null)
|
|
||||||
DB.query("SELECT quantity, base FROM Vault WHERE floID=? AND asset=? AND base IS NOT NULL ORDER BY base", [sellOrder.floID, asset]).then(result => {
|
|
||||||
let rem = sellOrder.quantity,
|
|
||||||
sell_base = 0,
|
|
||||||
base_quantity = 0;
|
|
||||||
for (let i = 0; i < result.length && rem > 0; i++) {
|
|
||||||
if (rem < result[i].quantity) {
|
|
||||||
sell_base += (rem * result[i].base);
|
|
||||||
base_quantity += rem;
|
|
||||||
rem = 0;
|
|
||||||
} else {
|
|
||||||
sell_base += (result[i].quantity * result[i].base);
|
|
||||||
base_quantity += result[i].quantity;
|
|
||||||
rem -= result[i].quantity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (base_quantity)
|
|
||||||
sell_base = sell_base / base_quantity;
|
|
||||||
if (sell_base > cur_price)
|
|
||||||
reject(false);
|
|
||||||
else
|
|
||||||
resolve(sellOrder);
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
else if (mode_null)
|
|
||||||
DB.query("SELECT IFNULL(SUM(quantity), 0) as total FROM Vault WHERE floID=? AND asset=?", [sellOrder.floID, asset]).then(result => {
|
|
||||||
if (result[0].total < sellOrder.quantity)
|
|
||||||
console.warn(`Sell Order ${sellOrder.id} was made without enough Assets. This should not happen`);
|
|
||||||
if (result[0].total > 0)
|
|
||||||
resolve(sellOrder);
|
|
||||||
else
|
|
||||||
reject(false);
|
|
||||||
}).catch(error => reject(error))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTopValidBuyOrder(orders, cur_price) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!orders.length)
|
|
||||||
return reject(false)
|
|
||||||
verifyBuyOrder(orders.pop(), cur_price) //pop: as the orders are sorted in ascending (highest point should be checked 1st)
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => {
|
|
||||||
if (error !== false)
|
|
||||||
return reject(error);
|
|
||||||
getTopValidBuyOrder(orders, cur_price)
|
|
||||||
.then(result => resolve(result))
|
|
||||||
.catch(error => reject(error));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifyBuyOrder(buyOrder, cur_price) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
DB.query("SELECT balance FROM Cash WHERE floID=?", [buyOrder.floID]).then(result => {
|
|
||||||
if (!result.length || result[0].balance < cur_price * buyOrder.quantity) {
|
|
||||||
//This should not happen unless a buy order is placed when user doesnt have enough cash balance
|
|
||||||
console.warn(`Buy order ${buyOrder.id} is active, but Cash is insufficient`);
|
|
||||||
reject(false);
|
|
||||||
} else
|
|
||||||
resolve(buyOrder);
|
|
||||||
}).catch(error => reject(error));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
addTag,
|
|
||||||
removeTag,
|
|
||||||
addDistributor,
|
|
||||||
removeDistributor,
|
|
||||||
checkDistributor,
|
|
||||||
getBestPairs,
|
|
||||||
set DB(db) {
|
|
||||||
DB = db;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -75,7 +75,7 @@ function refreshDataFromBlockchain() {
|
|||||||
promises.push(DB.query("DELETE FROM TagList WHERE tag=?", [t]));
|
promises.push(DB.query("DELETE FROM TagList WHERE tag=?", [t]));
|
||||||
if (content.Tag.add)
|
if (content.Tag.add)
|
||||||
for (let t in content.Tag.add)
|
for (let t in content.Tag.add)
|
||||||
promises.push(DB.query("INSERT INTO TagList (tag, sellPriority, buyPriority, api) VALUE (?,?,?,?) ON DUPLICATE KEY UPDATE tag=tag", [t, content.Tag.add[t].sellPriority, content.Tag.add[t].buyPriority, content.Tag.add[t].api]));
|
promises.push(DB.query("INSERT INTO TagList (tag, sellPriority, buyPriority) VALUE (?, ?, ?) ON DUPLICATE KEY UPDATE tag=tag", [t, content.Tag.add[t].sellPriority, content.Tag.add[t].buyPriority, content.Tag.add[t].api]));
|
||||||
if (content.Tag.update)
|
if (content.Tag.update)
|
||||||
for (let t in content.Tag.update)
|
for (let t in content.Tag.update)
|
||||||
for (let a in content.Tag.update[t])
|
for (let a in content.Tag.update[t])
|
||||||
|
|||||||
127
src/market.js
127
src/market.js
@ -3,13 +3,17 @@
|
|||||||
const coupling = require('./coupling');
|
const coupling = require('./coupling');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
MINIMUM_BUY_REQUIREMENT,
|
MAXIMUM_LAUNCH_SELL_CHIPS,
|
||||||
TRADE_HASH_PREFIX,
|
TRADE_HASH_PREFIX,
|
||||||
TRANSFER_HASH_PREFIX
|
TRANSFER_HASH_PREFIX
|
||||||
} = require('./_constants')["market"];
|
} = require('./_constants')["market"];
|
||||||
|
|
||||||
|
const LAUNCH_SELLER_TAG = "launch-seller";
|
||||||
|
|
||||||
const MINI_PERIOD_INTERVAL = require('./_constants')['app']['PERIOD_INTERVAL'] / 10;
|
const MINI_PERIOD_INTERVAL = require('./_constants')['app']['PERIOD_INTERVAL'] / 10;
|
||||||
|
|
||||||
|
const updateBalance = coupling.updateBalance;
|
||||||
|
|
||||||
var DB, assetList; //container for database and allowed assets
|
var DB, assetList; //container for database and allowed assets
|
||||||
|
|
||||||
function login(floID, proxyKey) {
|
function login(floID, proxyKey) {
|
||||||
@ -119,10 +123,6 @@ getAssetBalance.check = (floID, asset, amount) => new Promise((resolve, reject)
|
|||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateBalance = {};
|
|
||||||
updateBalance.consume = (floID, token, amount) => ["UPDATE UserBalance SET quantity=quantity-? WHERE floID=? AND token=?", [amount, floID, token]];
|
|
||||||
updateBalance.add = (floID, token, amount) => ["INSERT INTO UserBalance (floID, token, quantity) VALUE (?, ?, ?) ON DUPLICATE KEY UPDATE quantity=quantity+?", [floID, token, amount, amount]];
|
|
||||||
|
|
||||||
function addSellOrder(floID, asset, quantity, min_price) {
|
function addSellOrder(floID, asset, quantity, min_price) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateAddr(floID))
|
if (!floCrypto.validateAddr(floID))
|
||||||
@ -143,17 +143,17 @@ function addSellOrder(floID, asset, quantity, min_price) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkSellRequirement = (floID, asset) => new Promise((resolve, reject) => {
|
const checkSellRequirement = (floID, asset, quantity) => new Promise((resolve, reject) => {
|
||||||
DB.query("SELECT * FROM UserTag WHERE floID=? AND tag=?", [floID, "MINER"]).then(result => {
|
Promise.all([
|
||||||
if (result.length)
|
DB.query("SELECT IFNULL(SUM(quantity), 0) AS total_chips FROM SellChips WHERE floID=? AND asset=?", [floID, asset]),
|
||||||
return resolve(true);
|
DB.query("SELECT IFNULL(SUM(quantity), 0) AS locked FROM SellOrder WHERE floID=? AND asset=?", [floID, asset])
|
||||||
//TODO: Should seller need to buy same type of asset before selling?
|
]).then(result => {
|
||||||
DB.query("SELECT IFNULL(SUM(quantity), 0) AS brought FROM TradeTransactions WHERE buyer=? AND asset=?", [floID, asset]).then(result => {
|
let total = result[0].total_chips,
|
||||||
if (result[0].brought >= MINIMUM_BUY_REQUIREMENT)
|
locked = result[1].locked;
|
||||||
resolve(true);
|
if (total > locked + quantity)
|
||||||
else
|
resolve(true);
|
||||||
reject(INVALID(`Sellers required to buy atleast ${MINIMUM_BUY_REQUIREMENT} ${asset} before placing a sell order unless they are a Miner`));
|
else
|
||||||
}).catch(error => reject(error))
|
reject(INVALID(`Insufficient sell-chips for ${asset}`));
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ function transferToken(sender, receivers, token) {
|
|||||||
txQueries.push(updateBalance.consume(sender, token, totalAmount));
|
txQueries.push(updateBalance.consume(sender, token, totalAmount));
|
||||||
for (let floID in receivers)
|
for (let floID in receivers)
|
||||||
txQueries.push(updateBalance.add(floID, token, receivers[floID]));
|
txQueries.push(updateBalance.add(floID, token, receivers[floID]));
|
||||||
coupling.group.checkDistributor(sender, token).then(result => {
|
checkDistributor(sender, token).then(result => {
|
||||||
if (result)
|
if (result)
|
||||||
for (let floID in receivers)
|
for (let floID in receivers)
|
||||||
txQueries.push(["INSERT INTO Vault (floID, asset, quantity) VALUES (?, ?, ?)", [floID, token, receivers[floID]]]);
|
txQueries.push(["INSERT INTO Vault (floID, asset, quantity) VALUES (?, ?, ?)", [floID, token, receivers[floID]]]);
|
||||||
@ -332,6 +332,7 @@ function confirmDepositFLO() {
|
|||||||
let txQueries = [];
|
let txQueries = [];
|
||||||
txQueries.push(updateBalance.add(req.floID, "FLO", amount));
|
txQueries.push(updateBalance.add(req.floID, "FLO", amount));
|
||||||
txQueries.push(["UPDATE InputFLO SET status=?, amount=? WHERE id=?", ["SUCCESS", amount, req.id]]);
|
txQueries.push(["UPDATE InputFLO SET status=?, amount=? WHERE id=?", ["SUCCESS", amount, req.id]]);
|
||||||
|
|
||||||
DB.transaction(txQueries)
|
DB.transaction(txQueries)
|
||||||
.then(result => console.debug("FLO deposited:", req.floID, amount))
|
.then(result => console.debug("FLO deposited:", req.floID, amount))
|
||||||
.catch(error => console.error(error))
|
.catch(error => console.error(error))
|
||||||
@ -369,6 +370,31 @@ confirmDepositFLO.checkTx = function(sender, txid) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
confirmDepositFLO.addSellChipsIfLaunchSeller = function(floID, quantity) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
checkTag(req.floID, LAUNCH_SELLER_TAG).then(result => {
|
||||||
|
if (result) //floID is launch-seller
|
||||||
|
Promise.all([
|
||||||
|
DB.query("SELECT SUM(quantity) FROM TradeTransactions WHERE seller=? AND asset=?", [floID, 'FLO']),
|
||||||
|
DB.query("SELECT SUM(quantity) FROM TradeTransactions WHERE buyer=? AND asset=?", [floID, 'FLO']),
|
||||||
|
DB.query("SELECT SUM(quantity) FROM SellChips WHERE floID=? AND asset=?", [floID, 'FLO']),
|
||||||
|
]).then(result => {
|
||||||
|
let sold = result[0],
|
||||||
|
brought = result[1],
|
||||||
|
chips = result[2];
|
||||||
|
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))
|
||||||
@ -563,6 +589,68 @@ function confirmWithdrawalToken() {
|
|||||||
}).catch(error => console.error(error));
|
}).catch(error => console.error(error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addTag(floID, tag) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
DB.query("INSERT INTO UserTag (floID, tag) VALUE (?,?)", [floID, tag])
|
||||||
|
.then(result => resolve(`Added ${floID} to ${tag}`))
|
||||||
|
.catch(error => {
|
||||||
|
if (error.code === "ER_DUP_ENTRY")
|
||||||
|
reject(INVALID(`${floID} already in ${tag}`));
|
||||||
|
else if (error.code === "ER_NO_REFERENCED_ROW")
|
||||||
|
reject(INVALID(`Invalid Tag`));
|
||||||
|
else
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeTag(floID, tag) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
DB.query("DELETE FROM UserTag WHERE floID=? AND tag=?", [floID, tag])
|
||||||
|
.then(result => resolve(`Removed ${floID} from ${tag}`))
|
||||||
|
.catch(error => reject(error));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkTag(floID, tag) {
|
||||||
|
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) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
DB.query("INSERT INTO Distributors (floID, asset) VALUE (?,?)", [floID, asset])
|
||||||
|
.then(result => resolve(`Added ${asset} distributor: ${floID}`))
|
||||||
|
.catch(error => {
|
||||||
|
if (error.code === "ER_DUP_ENTRY")
|
||||||
|
reject(INVALID(`${floID} is already ${asset} disributor`));
|
||||||
|
else if (error.code === "ER_NO_REFERENCED_ROW")
|
||||||
|
reject(INVALID(`Invalid Asset`));
|
||||||
|
else
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDistributor(floID, asset) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
DB.query("DELETE FROM Distributors WHERE floID=? AND tag=?", [floID, asset])
|
||||||
|
.then(result => resolve(`Removed ${asset} distributor: ${floID}`))
|
||||||
|
.catch(error => reject(error));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkDistributor(floID, asset) {
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
DB.query("SELECT id FROM Distributors WHERE floID=? AND asset=?", [floID, asset])
|
||||||
|
.then(result => resolve(result.length ? true : false))
|
||||||
|
.catch(error => reject(error))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function periodicProcess() {
|
function periodicProcess() {
|
||||||
blockchainReCheck();
|
blockchainReCheck();
|
||||||
assetList.forEach(asset => coupling.initiate(asset));
|
assetList.forEach(asset => coupling.initiate(asset));
|
||||||
@ -603,8 +691,11 @@ module.exports = {
|
|||||||
withdrawFLO,
|
withdrawFLO,
|
||||||
depositToken,
|
depositToken,
|
||||||
withdrawToken,
|
withdrawToken,
|
||||||
|
addTag,
|
||||||
|
removeTag,
|
||||||
|
addDistributor,
|
||||||
|
removeDistributor,
|
||||||
periodicProcess,
|
periodicProcess,
|
||||||
group: coupling.group,
|
|
||||||
set DB(db) {
|
set DB(db) {
|
||||||
DB = db;
|
DB = db;
|
||||||
coupling.DB = db;
|
coupling.DB = db;
|
||||||
|
|||||||
@ -263,7 +263,7 @@ function AddUserTag(req, res) {
|
|||||||
tag: data.tag,
|
tag: data.tag,
|
||||||
timestamp: data.timestamp
|
timestamp: data.timestamp
|
||||||
}, data.sign, data.floID, data.pubKey,
|
}, data.sign, data.floID, data.pubKey,
|
||||||
() => market.group.addTag(data.user, data.tag)
|
() => market.addTag(data.user, data.tag)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ function RemoveUserTag(req, res) {
|
|||||||
tag: data.tag,
|
tag: data.tag,
|
||||||
timestamp: data.timestamp
|
timestamp: data.timestamp
|
||||||
}, data.sign, data.floID, data.pubKey,
|
}, data.sign, data.floID, data.pubKey,
|
||||||
() => market.group.removeTag(data.user, data.tag)
|
() => market.removeTag(data.user, data.tag)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +291,7 @@ function AddDistributor(req, res) {
|
|||||||
asset: data.asset,
|
asset: data.asset,
|
||||||
timestamp: data.timestamp
|
timestamp: data.timestamp
|
||||||
}, data.sign, data.floID, data.pubKey,
|
}, data.sign, data.floID, data.pubKey,
|
||||||
() => market.group.addDistributor(data.distributor, data.asset)
|
() => market.addDistributor(data.distributor, data.asset)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +305,7 @@ function RemoveDistributor(req, res) {
|
|||||||
asset: data.asset,
|
asset: data.asset,
|
||||||
timestamp: data.timestamp
|
timestamp: data.timestamp
|
||||||
}, data.sign, data.floID, data.pubKey,
|
}, data.sign, data.floID, data.pubKey,
|
||||||
() => market.group.removeDistributor(data.distributor, data.asset)
|
() => market.removeDistributor(data.distributor, data.asset)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user