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:
sairajzero 2022-04-17 03:44:34 +05:30
parent 9caf3fc9ec
commit f9551c856d
7 changed files with 281 additions and 568 deletions

View File

@ -16,13 +16,12 @@ CREATE TABLE TagList (
tag VARCHAR(50) NOT NULL,
sellPriority INT,
buyPriority INT,
api TINYTEXT,
PRIMARY KEY(tag)
);
CREATE TABLE AssetList (
asset VARCHAR(64) NOT NULL,
initialPrice FLOAT,
initialPrice DECIMAL(10, 2),
PRIMARY KEY(asset)
);
@ -42,21 +41,22 @@ CREATE TABLE UserSession (
PRIMARY KEY(floID)
);
CREATE TABLE Cash (
CREATE TABLE UserBalance (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL UNIQUE,
balance DECIMAL(12, 2) DEFAULT 0.00,
KEY(id),
PRIMARY KEY(floID)
);
floID CHAR(34) NOT NULL,
token VARCHAR(64) NOT NULL,
quantity DECIMAL(10, 2) NOT NULL DEFAULT 0,
PRIMARY KEY(floID, token),
KEY(id)
)
CREATE TABLE Vault (
CREATE TABLE SellChips (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
locktime DATETIME DEFAULT CURRENT_TIMESTAMP,
asset VARCHAR(64) NOT NULL,
base DECIMAL(10, 2),
quantity FLOAT NOT NULL,
base DECIMAL(10, 2) NOT NULL DEFAULT 0,
quantity DECIMAL(10, 2) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (asset) REFERENCES AssetList(asset)
);
@ -70,6 +70,15 @@ CREATE TABLE UserTag (
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 */
CREATE TABLE RequestLog(
@ -87,7 +96,7 @@ CREATE TABLE SellOrder (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
asset VARCHAR(64) NOT NULL,
quantity FLOAT NOT NULL,
quantity DECIMAL(10, 2) NOT NULL,
minPrice DECIMAL(10, 2) NOT NULL,
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(id),
@ -98,7 +107,7 @@ CREATE TABLE BuyOrder (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
asset VARCHAR(64) NOT NULL,
quantity FLOAT NOT NULL,
quantity DECIMAL(10, 2) NOT NULL,
maxPrice DECIMAL(10, 2) NOT NULL,
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(id),
@ -109,7 +118,7 @@ CREATE TABLE InputFLO (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128) NOT NULL,
floID CHAR(34) NOT NULL,
amount FLOAT,
amount DECIMAL(10, 2),
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id)
);
@ -118,7 +127,7 @@ CREATE TABLE OutputFLO (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128),
floID CHAR(34) NOT NULL,
amount FLOAT NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id)
);
@ -128,7 +137,7 @@ CREATE TABLE InputToken (
txid VARCHAR(128) NOT NULL,
floID CHAR(34) NOT NULL,
token VARCHAR(64),
amount FLOAT,
amount DECIMAL(10, 2),
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id)
);
@ -138,7 +147,7 @@ CREATE TABLE OutputToken (
txid VARCHAR(128),
floID CHAR(34) NOT NULL,
token VARCHAR(64),
amount FLOAT NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id)
);
@ -148,7 +157,7 @@ CREATE TABLE OutputToken (
CREATE TABLE PriceHistory (
id INT NOT NULL AUTO_INCREMENT,
asset VARCHAR(64) NOT NULL,
rate FLOAT NOT NULL,
rate DECIMAL(10, 2) NOT NULL,
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(id),
FOREIGN KEY (asset) REFERENCES AssetList(asset)
@ -159,7 +168,7 @@ CREATE TABLE TransferTransactions (
sender CHAR(34) NOT NULL,
receiver TEXT NOT NULL,
token VARCHAR(64) NOT NULL,
totalAmount FLOAT NOT NULL,
totalAmount DECIMAL(10, 2) NOT NULL,
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
txid VARCHAR(66) NOT NULL,
KEY(id),
@ -171,7 +180,7 @@ CREATE TABLE TradeTransactions (
seller CHAR(34) NOT NULL,
buyer CHAR(34) NOT NULL,
asset VARCHAR(64) NOT NULL,
quantity FLOAT NOT NULL,
quantity DECIMAL(10, 2) NOT NULL,
unitValue DECIMAL(10, 2) NOT NULL,
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
txid VARCHAR(66) NOT NULL,
@ -183,20 +192,20 @@ CREATE TABLE TradeTransactions (
CREATE TABLE AuditTrade(
id INT NOT NULL AUTO_INCREMENT,
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
unit_price FLOAT NOT NULL,
quantity FLOAT NOT NULL,
total_cost FLOAT NOT NULL,
unit_price DECIMAL(10, 2) NOT NULL,
quantity DECIMAL(10, 2) NOT NULL,
total_cost DECIMAL(10, 2) NOT NULL,
asset VARCHAR(64) NOT NULL,
sellerID CHAR(34) NOT NULL,
seller_old_asset FLOAT NOT NULL,
seller_new_asset FLOAT NOT NULL,
seller_old_cash FLOAT NOT NULL,
seller_new_cash FLOAT NOT NULL,
seller_old_asset DECIMAL(10, 2) NOT NULL,
seller_new_asset DECIMAL(10, 2) NOT NULL,
seller_old_cash DECIMAL(10, 2) NOT NULL,
seller_new_cash DECIMAL(10, 2) NOT NULL,
buyerID CHAR(34) NOT NULL,
buyer_old_asset FLOAT NOT NULL,
buyer_new_asset FLOAT NOT NULL,
buyer_old_cash FLOAT NOT NULL,
buyer_new_cash FLOAT NOT NULL,
buyer_old_asset DECIMAL(10, 2) NOT NULL,
buyer_new_asset DECIMAL(10, 2) NOT NULL,
buyer_old_cash DECIMAL(10, 2) NOT NULL,
buyer_new_cash DECIMAL(10, 2) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (asset) REFERENCES AssetList(asset)
);
@ -204,7 +213,7 @@ CREATE TABLE AuditTrade(
/* Backup Feature (Tables & Triggers) */
CREATE TABLE _backup (
t_name VARCHAR(20),
t_name TINYTEXT,
id INT,
mode BOOLEAN DEFAULT TRUE,
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
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
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Cash_U AFTER UPDATE ON Cash
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Cash_D AFTER DELETE ON Cash
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER UserBalance_I AFTER INSERT ON UserBalance
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserBalance', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER UserBalance_U AFTER UPDATE ON UserBalance
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserBalance', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER UserBalance_D AFTER DELETE ON UserBalance
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
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Vault', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Vault_U AFTER UPDATE ON Vault
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Vault', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Vault_D AFTER DELETE ON Vault
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Vault', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER SellChips_I AFTER INSERT ON SellChips
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('SellChips', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER SellChips_U AFTER UPDATE ON SellChips
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('SellChips', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER SellChips_D AFTER DELETE ON SellChips
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
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
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
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

View File

@ -9,7 +9,7 @@ module.exports = {
INVALID_SERVER_MSG: "INCORRECT_SERVER_ERROR" //Should be reflected in public backend script
},
market: {
MINIMUM_BUY_REQUIREMENT: 0,
MAXIMUM_LAUNCH_SELL_CHIPS: 1000000,
TRADE_HASH_PREFIX: "z1",
TRANSFER_HASH_PREFIX: "z0"
},

View File

@ -1,6 +1,5 @@
'use strict';
const group = require("./group");
const price = require("./price");
const {
@ -9,42 +8,84 @@ const {
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) {
price.getRates(asset).then(cur_rate => {
cur_rate = cur_rate.toFixed(8);
group.getBestPairs(asset, cur_rate)
.then(bestPairQueue => processCoupling(bestPairQueue))
.catch(error => console.error("initiateCoupling", error))
processCoupling(asset, cur_rate);
}).catch(error => console.error(error));
}
function processCoupling(bestPairQueue) {
bestPairQueue.get().then(pair_result => {
let buyer_best = pair_result.buyOrder,
seller_best = pair_result.sellOrder;
//console.debug("Sell:", seller_best);
//console.debug("Buy:", buyer_best);
spendAsset(bestPairQueue.asset, buyer_best, seller_best, pair_result.null_base).then(spent => {
if (!spent.quantity) {
//Happens when there are only Null-base assets
bestPairQueue.next(spent.quantity, spent.incomplete);
processCoupling(bestPairQueue);
return;
}
let txQueries = spent.txQueries;
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 => {
//process txn query in SQL
DB.transaction(txQueries).then(_ => {
bestPairQueue.next(spent.quantity, spent.incomplete);
console.log(`Transaction was successful! BuyOrder:${buyer_best.id}| SellOrder:${seller_best.id}`);
audit.end();
price.updateLastTime();
//Since a tx was successful, match again
processCoupling(bestPairQueue);
}).catch(error => console.error(error));
function getBestPair(asset, cur_rate) {
return new Promise((resolve, reject) => {
Promise.allSettled([getBestBuyer(asset, cur_rate), getBestSeller(asset, cur_rate)]).then(results => {
if (results[0].status === "fulfilled" && results[1].status === "fulfilled")
resolve({
buy: results[0].value,
sell: results[1].value,
})
else
reject({
buy: results[0].reason,
sell: results[1].reason
})
}).catch(error => reject(error))
})
}
const getBestSeller = (asset, cur_rate) => new Promise((resolve, reject) => {
DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity, SellChips.id AS chip_id, SellChips.quantity AS chip_quantity FROM SellOrder" +
" INNER JOIN UserBalance ON UserBalance.floID = SellOrder.floID AND UserBalance.token = SellOrder.asset" +
" INNER JOIN SellChips ON SellChips.floID = SellOrder.floID AND SellChips.asset = SellOrder.asset AND SellChips.base <= ?" +
" LEFT JOIN UserTag ON UserTag.floID = SellOrder.floID" +
" LEFT JOIN TagList ON TagList.tag = UserTag.tag" +
" WHERE UserBalance.quantity >= SellOrder.quantity AND SellOrder.asset = ? AND SellOrder.minPrice <= ?" +
" ORDER BY TagList.sellPriority DESC, SellChips.locktime ASC, SellOrder.time_placed ASC" +
" LIMIT 1", [cur_rate, asset, cur_rate]
).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 => {
@ -55,7 +96,7 @@ function processCoupling(bestPairQueue) {
console.error(error.buy);
noBuy = null;
} else {
console.log("No valid buyOrders for Asset:", bestPairQueue.asset);
console.log("No valid buyOrders for Asset:", asset);
noBuy = true;
}
if (error.sell === undefined)
@ -64,37 +105,14 @@ function processCoupling(bestPairQueue) {
console.error(error.sell);
noSell = null;
} else {
console.log("No valid sellOrders for Asset:", bestPairQueue.asset);
console.log("No valid sellOrders for Asset:", asset);
noSell = true;
}
price.noOrder(bestPairQueue.asset, noBuy, noSell);
price.noOrder(asset, noBuy, noSell);
});
}
function spendAsset(asset, buyOrder, sellOrder, null_base) {
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) {
function processOrders(seller_best, buyer_best, txQueries, quantity) {
if (quantity > buyer_best.quantity || quantity > seller_best.quantity)
throw Error("Tx quantity cannot be more than order quantity");
//Process Buy Order
@ -103,19 +121,26 @@ function processOrders(seller_best, buyer_best, txQueries, quantity, clear_sell)
else
txQueries.push(["UPDATE BuyOrder SET quantity=quantity-? WHERE id=?", [quantity, buyer_best.id]]);
//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]]);
else
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) {
//Update cash balance for seller and buyer
//Update cash/asset balance for seller and buyer
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(["UPDATE Cash SET balance=balance-? WHERE floID=?", [totalAmount, buyer_best.floID]]);
//Add coins to Buyer
txQueries.push(["INSERT INTO Vault(floID, asset, base, quantity) VALUES (?, ?, ?, ?)", [buyer_best.floID, asset, cur_price, quantity]])
txQueries.push(updateBalance.add(seller_best.floID, floGlobals.currency, totalAmount));
txQueries.push(updateBalance.consume(buyer_best.floID, floGlobals.currency, totalAmount));
txQueries.push(updateBalance.add(seller_best.floID, asset, totalAmount));
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
let time = Date.now();
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) {
return new Promise((resolve, reject) => {
let balance = {
[sellerID]: {},
[buyerID]: {}
[sellerID]: {
cash: 0,
asset: 0
},
[buyerID]: {
cash: 0,
asset: 0
}
};
DB.query("SELECT floID, balance FROM Cash WHERE floID IN (?, ?)", [sellerID, buyerID]).then(result => {
for (let i in result)
balance[result[i].floID].cash = result[i].balance;
DB.query("SELECT floID, SUM(quantity) as asset_balance FROM Vault WHERE asset=? AND floID IN (?, ?) GROUP BY floID", [asset, sellerID, buyerID]).then(result => {
for (let i in result)
balance[result[i].floID].asset = result[i].asset_balance;
//Set them as 0 if undefined or null
balance[sellerID].cash = balance[sellerID].cash || 0;
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))
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) {
if (result[i].token === floGlobals.currency)
balance[result[i].floID].cash = result[i].quantity;
else if (result[i].token === asset)
balance[result[i].floID].asset = result[i].quantity;
}
resolve(balance);
}).catch(error => reject(error))
})
}
module.exports = {
initiate: startCouplingForAsset,
group: group,
updateBalance,
price,
set DB(db) {
DB = db;
group.DB = db;
price.DB = db;
}
}

View File

@ -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;
}
};

View File

@ -75,7 +75,7 @@ function refreshDataFromBlockchain() {
promises.push(DB.query("DELETE FROM TagList WHERE tag=?", [t]));
if (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)
for (let t in content.Tag.update)
for (let a in content.Tag.update[t])

View File

@ -3,13 +3,17 @@
const coupling = require('./coupling');
const {
MINIMUM_BUY_REQUIREMENT,
MAXIMUM_LAUNCH_SELL_CHIPS,
TRADE_HASH_PREFIX,
TRANSFER_HASH_PREFIX
} = require('./_constants')["market"];
const LAUNCH_SELLER_TAG = "launch-seller";
const MINI_PERIOD_INTERVAL = require('./_constants')['app']['PERIOD_INTERVAL'] / 10;
const updateBalance = coupling.updateBalance;
var DB, assetList; //container for database and allowed assets
function login(floID, proxyKey) {
@ -119,10 +123,6 @@ getAssetBalance.check = (floID, asset, amount) => new Promise((resolve, reject)
}).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) {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(floID))
@ -143,17 +143,17 @@ function addSellOrder(floID, asset, quantity, min_price) {
});
}
const checkSellRequirement = (floID, asset) => new Promise((resolve, reject) => {
DB.query("SELECT * FROM UserTag WHERE floID=? AND tag=?", [floID, "MINER"]).then(result => {
if (result.length)
return resolve(true);
//TODO: Should seller need to buy same type of asset before selling?
DB.query("SELECT IFNULL(SUM(quantity), 0) AS brought FROM TradeTransactions WHERE buyer=? AND asset=?", [floID, asset]).then(result => {
if (result[0].brought >= MINIMUM_BUY_REQUIREMENT)
resolve(true);
else
reject(INVALID(`Sellers required to buy atleast ${MINIMUM_BUY_REQUIREMENT} ${asset} before placing a sell order unless they are a Miner`));
}).catch(error => reject(error))
const checkSellRequirement = (floID, asset, quantity) => new Promise((resolve, reject) => {
Promise.all([
DB.query("SELECT IFNULL(SUM(quantity), 0) AS total_chips FROM SellChips WHERE floID=? AND asset=?", [floID, asset]),
DB.query("SELECT IFNULL(SUM(quantity), 0) AS locked FROM SellOrder WHERE floID=? AND asset=?", [floID, asset])
]).then(result => {
let total = result[0].total_chips,
locked = result[1].locked;
if (total > locked + quantity)
resolve(true);
else
reject(INVALID(`Insufficient sell-chips for ${asset}`));
}).catch(error => reject(error))
});
@ -280,7 +280,7 @@ function transferToken(sender, receivers, token) {
txQueries.push(updateBalance.consume(sender, token, totalAmount));
for (let floID in receivers)
txQueries.push(updateBalance.add(floID, token, receivers[floID]));
coupling.group.checkDistributor(sender, token).then(result => {
checkDistributor(sender, token).then(result => {
if (result)
for (let floID in receivers)
txQueries.push(["INSERT INTO Vault (floID, asset, quantity) VALUES (?, ?, ?)", [floID, token, receivers[floID]]]);
@ -332,6 +332,7 @@ function confirmDepositFLO() {
let 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))
@ -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) {
return new Promise((resolve, reject) => {
if (!floCrypto.validateAddr(floID))
@ -563,6 +589,68 @@ function confirmWithdrawalToken() {
}).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() {
blockchainReCheck();
assetList.forEach(asset => coupling.initiate(asset));
@ -603,8 +691,11 @@ module.exports = {
withdrawFLO,
depositToken,
withdrawToken,
addTag,
removeTag,
addDistributor,
removeDistributor,
periodicProcess,
group: coupling.group,
set DB(db) {
DB = db;
coupling.DB = db;

View File

@ -263,7 +263,7 @@ function AddUserTag(req, res) {
tag: data.tag,
timestamp: data.timestamp
}, 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,
timestamp: data.timestamp
}, 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,
timestamp: data.timestamp
}, 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,
timestamp: data.timestamp
}, data.sign, data.floID, data.pubKey,
() => market.group.removeDistributor(data.distributor, data.asset)
() => market.removeDistributor(data.distributor, data.asset)
);
}