Merge branch 'sairajzero:main' into main

This commit is contained in:
Sai Raj 2022-02-07 03:35:51 +05:30 committed by GitHub
commit 8a967eb9fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 795 additions and 655 deletions

View File

@ -1,201 +1,226 @@
/* Main Tables */ /* Blockchain Data */
CREATE TABLE Users ( CREATE TABLE LastTx(
floID CHAR(34) NOT NULL, floID CHAR(34) NOT NULL,
pubKey CHAR(66) NOT NULL, num INT,
created DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(floID)
PRIMARY KEY(floID)
); );
CREATE TABLE Sessions ( CREATE TABLE NodeList(
id INT NOT NULL AUTO_INCREMENT, floID CHAR(34) NOT NULL,
floID CHAR(34) NOT NULL, uri TINYTEXT,
proxyKey CHAR(66) NOT NULL, PRIMARY KEY(floID)
session_time DATETIME DEFAULT CURRENT_TIMESTAMP,
KEY (id),
PRIMARY KEY(floID),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE Request_Log(
floID CHAR(34) NOT NULL,
request TEXT NOT NULL,
sign TEXT NOT NULL,
request_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE Cash (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL UNIQUE,
rupeeBalance DECIMAL(12, 2) DEFAULT 0.00,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE Vault (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
locktime DATETIME DEFAULT CURRENT_TIMESTAMP,
base DECIMAL(10, 2),
quantity FLOAT NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE SellOrder (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
quantity FLOAT NOT NULL,
minPrice DECIMAL(10, 2),
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE BuyOrder (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
quantity FLOAT NOT NULL,
maxPrice DECIMAL(10, 2) NOT NULL,
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE Transactions (
seller CHAR(34) NOT NULL,
buyer CHAR(34) NOT NULL,
quantity FLOAT NOT NULL,
unitValue DECIMAL(10, 2) NOT NULL,
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (buyer) REFERENCES Users(floID),
FOREIGN KEY (seller) REFERENCES Users(floID)
);
CREATE TABLE inputFLO (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128) NOT NULL,
floID CHAR(34) NOT NULL,
amount FLOAT,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE outputFLO (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128),
floID CHAR(34) NOT NULL,
amount FLOAT NOT NULL,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE inputRupee (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128) NOT NULL,
floID CHAR(34) NOT NULL,
amount FLOAT,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE outputRupee (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128),
floID CHAR(34) NOT NULL,
amount FLOAT NOT NULL,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE lastTx(
floID CHAR(34) NOT NULL,
num INT,
PRIMARY KEY(floID)
);
CREATE TABLE nodeList(
floID CHAR(34) NOT NULL,
uri TINYTEXT,
PRIMARY KEY(floID)
);
CREATE TABLE trustedList(
floID CHAR(34) NOT NULL,
PRIMARY KEY(floID),
FOREIGN KEY (floID) REFERENCES Users(floID)
); );
CREATE TABLE TagList ( CREATE TABLE TagList (
tag VARCHAR(50) NOT NULL, tag VARCHAR(50) NOT NULL,
sellPriority INT, sellPriority INT,
buyPriority INT, buyPriority INT,
api TINYTEXT, api TINYTEXT,
PRIMARY KEY(tag) PRIMARY KEY(tag)
); );
CREATE TABLE Tags ( CREATE TABLE AssetList (
id INT NOT NULL AUTO_INCREMENT, asset VARCHAR(64) NOT NULL,
floID CHAR(34) NOT NULL, initialPrice FLOAT,
tag VARCHAR(50) NOT NULL, PRIMARY KEY(asset)
PRIMARY KEY(floID, tag),
KEY (id),
FOREIGN KEY (floID) REFERENCES Users(floID),
FOREIGN KEY (tag) REFERENCES TagList(tag)
); );
CREATE TABLE priceHistory ( CREATE TABLE TrustedList(
rate FLOAT NOT NULL, floID CHAR(34) NOT NULL,
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP PRIMARY KEY(floID)
); );
CREATE TABLE auditTransaction( /* User Data */
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
unit_price FLOAT NOT NULL, CREATE TABLE Users (
quantity FLOAT NOT NULL, floID CHAR(34) NOT NULL,
total_cost FLOAT NOT NULL, pubKey CHAR(66) NOT NULL,
sellerID CHAR(34) NOT NULL, created DATETIME DEFAULT CURRENT_TIMESTAMP,
FLO_seller_old FLOAT NOT NULL, PRIMARY KEY(floID)
FLO_seller_new FLOAT NOT NULL, );
Rupee_seller_old FLOAT NOT NULL,
Rupee_seller_new FLOAT NOT NULL, CREATE TABLE UserSession (
buyerID CHAR(34) NOT NULL, id INT NOT NULL AUTO_INCREMENT,
FLO_buyer_old FLOAT NOT NULL, floID CHAR(34) NOT NULL,
FLO_buyer_new FLOAT NOT NULL, proxyKey CHAR(66) NOT NULL,
Rupee_buyer_old FLOAT NOT NULL, session_time DATETIME DEFAULT CURRENT_TIMESTAMP,
Rupee_buyer_new FLOAT NOT NULL, KEY (id),
FOREIGN KEY (sellerID) REFERENCES Users(floID), PRIMARY KEY(floID),
FOREIGN KEY (buyerID) REFERENCES Users(floID) FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE Cash (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL UNIQUE,
balance DECIMAL(12, 2) DEFAULT 0.00,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE Vault (
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,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID),
FOREIGN KEY (asset) REFERENCES AssetList(asset)
);
CREATE TABLE UserTag (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
tag VARCHAR(50) NOT NULL,
PRIMARY KEY(floID, tag),
KEY (id),
FOREIGN KEY (floID) REFERENCES Users(floID),
FOREIGN KEY (tag) REFERENCES TagList(tag)
);
/* User Requests */
CREATE TABLE Request_Log(
floID CHAR(34) NOT NULL,
request TEXT NOT NULL,
sign TEXT NOT NULL,
request_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE SellOrder (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
asset VARCHAR(64) NOT NULL,
quantity FLOAT NOT NULL,
minPrice DECIMAL(10, 2),
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID),
FOREIGN KEY (asset) REFERENCES AssetList(asset)
);
CREATE TABLE BuyOrder (
id INT NOT NULL AUTO_INCREMENT,
floID CHAR(34) NOT NULL,
asset VARCHAR(64) NOT NULL,
quantity FLOAT NOT NULL,
maxPrice DECIMAL(10, 2) NOT NULL,
time_placed DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID),
FOREIGN KEY (asset) REFERENCES AssetList(asset)
);
CREATE TABLE InputFLO (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128) NOT NULL,
floID CHAR(34) NOT NULL,
amount FLOAT,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE OutputFLO (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128),
floID CHAR(34) NOT NULL,
amount FLOAT NOT NULL,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE InputToken (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128) NOT NULL,
floID CHAR(34) NOT NULL,
token VARCHAR(64),
amount FLOAT,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
CREATE TABLE OutputToken (
id INT NOT NULL AUTO_INCREMENT,
txid VARCHAR(128),
floID CHAR(34) NOT NULL,
token VARCHAR(64),
amount FLOAT NOT NULL,
status VARCHAR(50) NOT NULL,
PRIMARY KEY(id),
FOREIGN KEY (floID) REFERENCES Users(floID)
);
/* Transaction Data */
CREATE TABLE PriceHistory (
asset VARCHAR(64) NOT NULL,
rate FLOAT NOT NULL,
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (asset) REFERENCES AssetList(asset)
);
CREATE TABLE TransactionHistory (
seller CHAR(34) NOT NULL,
buyer CHAR(34) NOT NULL,
asset VARCHAR(64) NOT NULL,
quantity FLOAT NOT NULL,
unitValue DECIMAL(10, 2) NOT NULL,
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (buyer) REFERENCES Users(floID),
FOREIGN KEY (seller) REFERENCES Users(floID),
FOREIGN KEY (asset) REFERENCES AssetList(asset)
);
CREATE TABLE AuditTransaction(
rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
unit_price FLOAT NOT NULL,
quantity FLOAT NOT NULL,
total_cost FLOAT 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,
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,
FOREIGN KEY (sellerID) REFERENCES Users(floID),
FOREIGN KEY (buyerID) REFERENCES Users(floID),
FOREIGN KEY (asset) REFERENCES AssetList(asset)
);
/* Backup Feature (Tables & Triggers) */
CREATE TABLE _backup (
t_name VARCHAR(20),
id INT,
mode BOOLEAN DEFAULT TRUE,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(t_name, id)
); );
CREATE TABLE sinkShares( CREATE TABLE sinkShares(
floID CHAR(34) NOT NULL, floID CHAR(34) NOT NULL,
share TEXT, share TEXT,
time_ DATETIME DEFAULT CURRENT_TIMESTAMP, time_ DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(floID) PRIMARY KEY(floID)
); );
/* Backup feature (Table and Triggers) */ CREATE TRIGGER UserSession_I AFTER INSERT ON UserSession
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserSession', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TABLE _backup ( CREATE TRIGGER UserSession_U AFTER UPDATE ON UserSession
t_name VARCHAR(20), FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserSession', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
id INT, CREATE TRIGGER UserSession_D AFTER DELETE ON UserSession
mode BOOLEAN DEFAULT TRUE, FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserSession', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY(t_name, id)
);
CREATE TRIGGER Sessions_I AFTER INSERT ON Sessions
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Sessions', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Sessions_U AFTER UPDATE ON Sessions
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Sessions', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Sessions_D AFTER DELETE ON Sessions
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Sessions', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER Cash_I AFTER INSERT ON Cash 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; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
@ -225,37 +250,37 @@ FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('BuyOrder', NEW.id) ON DUP
CREATE TRIGGER BuyOrder_D AFTER DELETE ON BuyOrder CREATE TRIGGER BuyOrder_D AFTER DELETE ON BuyOrder
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('BuyOrder', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('BuyOrder', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER inputFLO_I AFTER INSERT ON inputFLO CREATE TRIGGER InputFLO_I AFTER INSERT ON InputFLO
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER inputFLO_U AFTER UPDATE ON inputFLO CREATE TRIGGER InputFLO_U AFTER UPDATE ON InputFLO
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER inputFLO_D AFTER DELETE ON inputFLO CREATE TRIGGER InputFLO_D AFTER DELETE ON InputFLO
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputFLO', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputFLO', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER outputFLO_I AFTER INSERT ON outputFLO CREATE TRIGGER OutputFLO_I AFTER INSERT ON OutputFLO
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER outputFLO_U AFTER UPDATE ON outputFLO CREATE TRIGGER OutputFLO_U AFTER UPDATE ON OutputFLO
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputFLO', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER outputFLO_D AFTER DELETE ON outputFLO CREATE TRIGGER OutputFLO_D AFTER DELETE ON OutputFLO
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputFLO', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputFLO', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER inputRupee_I AFTER INSERT ON inputRupee CREATE TRIGGER InputToken_I AFTER INSERT ON InputToken
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputRupee', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER inputRupee_U AFTER UPDATE ON inputRupee CREATE TRIGGER InputToken_U AFTER UPDATE ON InputToken
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputRupee', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER inputRupee_D AFTER DELETE ON inputRupee CREATE TRIGGER InputToken_D AFTER DELETE ON InputToken
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputRupee', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputToken', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER outputRupee_I AFTER INSERT ON outputRupee CREATE TRIGGER OutputToken_I AFTER INSERT ON OutputToken
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputRupee', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER outputRupee_U AFTER UPDATE ON outputRupee CREATE TRIGGER OutputToken_U AFTER UPDATE ON OutputToken
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputRupee', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER outputRupee_D AFTER DELETE ON outputRupee CREATE TRIGGER OutputToken_D AFTER DELETE ON OutputToken
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputRupee', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputToken', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER Tags_I AFTER INSERT ON Tags CREATE TRIGGER UserTag_I AFTER INSERT ON UserTag
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Tags', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserTag', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Tags_U AFTER UPDATE ON Tags CREATE TRIGGER UserTag_U AFTER UPDATE ON UserTag
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Tags', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserTag', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
CREATE TRIGGER Tags_D AFTER DELETE ON Tags CREATE TRIGGER UserTag_D AFTER DELETE ON UserTag
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Tags', 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;

View File

@ -1,23 +1,24 @@
/* Node data */ /* Node data */
TRUNCATE _backup; TRUNCATE _backup;
TRUNCATE auditTransaction; TRUNCATE AuditTransaction;
TRUNCATE BuyOrder; TRUNCATE BuyOrder;
TRUNCATE Cash; TRUNCATE Cash;
TRUNCATE inputFLO; TRUNCATE InputFLO;
TRUNCATE inputRupee; TRUNCATE InputToken;
TRUNCATE outputFLO; TRUNCATE OutputFLO;
TRUNCATE outputRupee; TRUNCATE OutputToken;
TRUNCATE priceHistory; TRUNCATE PriceHistory;
TRUNCATE Request_Log; TRUNCATE Request_Log;
TRUNCATE SellOrder; TRUNCATE SellOrder;
TRUNCATE Sessions; TRUNCATE UserSession;
TRUNCATE Tags; TRUNCATE UserTag;
TRUNCATE Transactions; TRUNCATE TransactionHistory;
TRUNCATE Vault; TRUNCATE Vault;
TRUNCATE Users; TRUNCATE Users;
/* Blockchain data */ /* Blockchain data */
TRUNCATE lastTx; TRUNCATE LastTx;
TRUNCATE nodeList; TRUNCATE NodeList;
TRUNCATE trustedList; TRUNCATE TrustedList;
TRUNCATE TagList; TRUNCATE TagList;
TRUNCATE AssetList;

View File

@ -13,7 +13,7 @@ const floGlobals = {
sendAmt: 0.001, sendAmt: 0.001,
fee: 0.0005, fee: 0.0005,
tokenURL: "https://ranchimallflo.duckdns.org/", tokenURL: "https://ranchimallflo.duckdns.org/",
token: "rupee" currency: "rupee"
}; };
(typeof global !== "undefined" ? global : window).cryptocoin = floGlobals.blockchain; (typeof global !== "undefined" ? global : window).cryptocoin = floGlobals.blockchain;

View File

@ -1,4 +1,5 @@
//console.log(document.cookie.toString()); //console.log(document.cookie.toString());
const INVALID_SERVER_MSG = "INCORRECT_SERVER_ERROR";
var nodeList, nodeURL, nodeKBucket; //Container for (backup) node list var nodeList, nodeURL, nodeKBucket; //Container for (backup) node list
function exchangeAPI(api, options) { function exchangeAPI(api, options) {
@ -52,7 +53,7 @@ const tokenAPI = {
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, },
sendToken: function(privKey, amount, receiverID, message = "", token = 'rupee') { sendToken: function(privKey, amount, receiverID, message = "", token = floGlobals.currency) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let senderID = floCrypto.getFloID(privKey); let senderID = floCrypto.getFloID(privKey);
if (typeof amount !== "number" || amount <= 0) if (typeof amount !== "number" || amount <= 0)
@ -69,7 +70,9 @@ const tokenAPI = {
} }
function ResponseError(status, data) { function ResponseError(status, data) {
if (this instanceof ResponseError) { if (data === INVALID_SERVER_MSG)
location.reload();
else if (this instanceof ResponseError) {
this.data = data; this.data = data;
this.status = status; this.status = status;
} else } else
@ -148,10 +151,10 @@ function getTransactionList() {
}); });
} }
function getRate() { function getRates() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
exchangeAPI('/get-rate') exchangeAPI('/get-rates')
.then(result => responseParse(result, false) .then(result => responseParse(result)
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error))) .catch(error => reject(error)))
.catch(error => reject(error)); .catch(error => reject(error));
@ -265,7 +268,7 @@ function logout(floID, proxySecret) {
}) })
} }
function buy(quantity, max_price, floID, proxySecret) { function buy(asset, quantity, max_price, floID, proxySecret) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (typeof quantity !== "number" || quantity <= 0) if (typeof quantity !== "number" || quantity <= 0)
return reject(`Invalid quantity (${quantity})`); return reject(`Invalid quantity (${quantity})`);
@ -273,12 +276,14 @@ function buy(quantity, max_price, floID, proxySecret) {
return reject(`Invalid max_price (${max_price})`); return reject(`Invalid max_price (${max_price})`);
let request = { let request = {
floID: floID, floID: floID,
asset: asset,
quantity: quantity, quantity: quantity,
max_price: max_price, max_price: max_price,
timestamp: Date.now() timestamp: Date.now()
}; };
request.sign = signRequest({ request.sign = signRequest({
type: "buy_order", type: "buy_order",
asset: asset,
quantity: quantity, quantity: quantity,
max_price: max_price, max_price: max_price,
timestamp: request.timestamp timestamp: request.timestamp
@ -299,7 +304,7 @@ function buy(quantity, max_price, floID, proxySecret) {
} }
function sell(quantity, min_price, floID, proxySecret) { function sell(asset, quantity, min_price, floID, proxySecret) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (typeof quantity !== "number" || quantity <= 0) if (typeof quantity !== "number" || quantity <= 0)
return reject(`Invalid quantity (${quantity})`); return reject(`Invalid quantity (${quantity})`);
@ -307,6 +312,7 @@ function sell(quantity, min_price, floID, proxySecret) {
return reject(`Invalid min_price (${min_price})`); return reject(`Invalid min_price (${min_price})`);
let request = { let request = {
floID: floID, floID: floID,
asset: asset,
quantity: quantity, quantity: quantity,
min_price: min_price, min_price: min_price,
timestamp: Date.now() timestamp: Date.now()
@ -314,6 +320,7 @@ function sell(quantity, min_price, floID, proxySecret) {
request.sign = signRequest({ request.sign = signRequest({
type: "sell_order", type: "sell_order",
quantity: quantity, quantity: quantity,
asset: asset,
min_price: min_price, min_price: min_price,
timestamp: request.timestamp timestamp: request.timestamp
}, proxySecret); }, proxySecret);
@ -376,7 +383,7 @@ function depositFLO(quantity, floID, sinkID, privKey, proxySecret) {
}; };
request.sign = signRequest({ request.sign = signRequest({
type: "deposit_FLO", type: "deposit_FLO",
txid: request.txid, txid: txid,
timestamp: request.timestamp timestamp: request.timestamp
}, proxySecret); }, proxySecret);
console.debug(request); console.debug(request);
@ -404,7 +411,7 @@ function withdrawFLO(quantity, floID, proxySecret) {
}; };
request.sign = signRequest({ request.sign = signRequest({
type: "withdraw_FLO", type: "withdraw_FLO",
amount: request.amount, amount: quantity,
timestamp: request.timestamp timestamp: request.timestamp
}, proxySecret); }, proxySecret);
console.debug(request); console.debug(request);
@ -422,24 +429,24 @@ function withdrawFLO(quantity, floID, proxySecret) {
}) })
} }
function depositRupee(quantity, floID, sinkID, privKey, proxySecret) { function depositToken(token, quantity, floID, sinkID, privKey, proxySecret) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!floCrypto.verifyPrivKey(privKey, floID)) if (!floCrypto.verifyPrivKey(privKey, floID))
return reject("Invalid Private Key"); return reject("Invalid Private Key");
tokenAPI.sendToken(privKey, quantity, sinkID, 'Deposit Rupee in market').then(txid => { tokenAPI.sendToken(privKey, quantity, sinkID, 'Deposit Rupee in market', token).then(txid => {
let request = { let request = {
floID: floID, floID: floID,
txid: txid, txid: txid,
timestamp: Date.now() timestamp: Date.now()
}; };
request.sign = signRequest({ request.sign = signRequest({
type: "deposit_Rupee", type: "deposit_Token",
txid: request.txid, txid: txid,
timestamp: request.timestamp timestamp: request.timestamp
}, proxySecret); }, proxySecret);
console.debug(request); console.debug(request);
exchangeAPI('/deposit-rupee', { exchangeAPI('/deposit-token', {
method: "POST", method: "POST",
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -453,21 +460,23 @@ function depositRupee(quantity, floID, sinkID, privKey, proxySecret) {
}) })
} }
function withdrawRupee(quantity, floID, proxySecret) { function withdrawToken(token, quantity, floID, proxySecret) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let request = { let request = {
floID: floID, floID: floID,
token: token,
amount: quantity, amount: quantity,
timestamp: Date.now() timestamp: Date.now()
}; };
request.sign = signRequest({ request.sign = signRequest({
type: "withdraw_Rupee", type: "withdraw_Token",
amount: request.amount, token: token,
amount: quantity,
timestamp: request.timestamp timestamp: request.timestamp
}, proxySecret); }, proxySecret);
console.debug(request); console.debug(request);
exchangeAPI('/withdraw-rupee', { exchangeAPI('/withdraw-token', {
method: "POST", method: "POST",
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@ -490,8 +499,8 @@ function addUserTag(tag_user, tag, floID, proxySecret) {
}; };
request.sign = signRequest({ request.sign = signRequest({
command: "add_Tag", command: "add_Tag",
user: request.user, user: tag_user,
tag: request.tag, tag: tag,
timestamp: request.timestamp timestamp: request.timestamp
}, proxySecret); }, proxySecret);
console.debug(request); console.debug(request);
@ -519,8 +528,8 @@ function removeUserTag(tag_user, tag, floID, proxySecret) {
}; };
request.sign = signRequest({ request.sign = signRequest({
command: "remove_Tag", command: "remove_Tag",
user: request.user, user: tag_user,
tag: request.tag, tag: tag,
timestamp: request.timestamp timestamp: request.timestamp
}, proxySecret); }, proxySecret);
console.debug(request); console.debug(request);

View File

@ -102,6 +102,7 @@
<strip-option value="sell">Sell</strip-option> <strip-option value="sell">Sell</strip-option>
</strip-select> </strip-select>
</div> </div>
<select id="get_asset"></select>
<sm-input id="get_price" variant="outlined" placeholder="Max price (₹)" type="number" step="0.01" <sm-input id="get_price" variant="outlined" placeholder="Max price (₹)" type="number" step="0.01"
required hiderequired animate> required hiderequired animate>
</sm-input> </sm-input>
@ -976,23 +977,23 @@
} }
const render = { const render = {
orderCard(orderDetails = {}) { orderCard(orderDetails = {}) {
const { id, quantity, price, time, type } = orderDetails const { id, asset, quantity, price, time, type } = orderDetails
const card = getRef('order_template').content.cloneNode(true).firstElementChild const card = getRef('order_template').content.cloneNode(true).firstElementChild
card.dataset.id = id card.dataset.id = id
card.dataset.type = type card.dataset.type = type
card.querySelector('.order-card__type').textContent = type card.querySelector('.order-card__type').textContent = type
card.querySelector('.order-card__quantity').textContent = `${quantity} FLO` card.querySelector('.order-card__quantity').textContent = `${quantity} ${asset}`
card.querySelector('.order-card__price-type').textContent = type === 'buy' ? 'Max price' : 'Min price' card.querySelector('.order-card__price-type').textContent = type === 'buy' ? 'Max price' : 'Min price'
card.querySelector('.order-card__price').textContent = formatAmount(price) card.querySelector('.order-card__price').textContent = formatAmount(price)
card.querySelector('.order-card__time').textContent = getFormattedTime(time, true) card.querySelector('.order-card__time').textContent = getFormattedTime(time, true)
return card return card
}, },
transactionCard(transactionDetails = {}) { transactionCard(transactionDetails = {}) {
const { buyer, seller, type, other, quantity, unitValue, time } = transactionDetails const { buyer, seller, type, other, asset, quantity, unitValue, time } = transactionDetails
const card = getRef('transaction_template').content.cloneNode(true).firstElementChild const card = getRef('transaction_template').content.cloneNode(true).firstElementChild
card.dataset.type = type card.dataset.type = type
card.querySelector('.transaction-card__type').textContent = type card.querySelector('.transaction-card__type').textContent = type
card.querySelector('.transaction-card__quantity').textContent = `${quantity} FLO` card.querySelector('.transaction-card__quantity').textContent = `${quantity} ${asset}`
card.querySelector('.transaction-card__price').textContent = formatAmount(unitValue) card.querySelector('.transaction-card__price').textContent = formatAmount(unitValue)
card.querySelector('.transaction-card__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2))) card.querySelector('.transaction-card__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2)))
card.querySelector('.more-info').dataset.buyer = buyer card.querySelector('.more-info').dataset.buyer = buyer
@ -1002,12 +1003,12 @@
return card return card
}, },
marketOrderCard(orderDetails = {}) { marketOrderCard(orderDetails = {}) {
const { floID, quantity, unitValue, time, type } = orderDetails const { floID, asset, quantity, unitValue, time, type } = orderDetails
const card = getRef('market_order_template').content.cloneNode(true).firstElementChild const card = getRef('market_order_template').content.cloneNode(true).firstElementChild
card.dataset.type = type card.dataset.type = type
card.classList.add(`transaction-card--${type}`) card.classList.add(`transaction-card--${type}`)
card.querySelector('.transaction-card__type').textContent = type card.querySelector('.transaction-card__type').textContent = type
card.querySelector('.transaction-card__quantity').textContent = `${quantity} FLO` card.querySelector('.transaction-card__quantity').textContent = `${quantity} ${asset}`
card.querySelector('.transaction-card__price').textContent = formatAmount(unitValue) card.querySelector('.transaction-card__price').textContent = formatAmount(unitValue)
card.querySelector('.transaction-card__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2))) card.querySelector('.transaction-card__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2)))
card.querySelector('.more-info').dataset.time = time card.querySelector('.more-info').dataset.time = time
@ -1017,9 +1018,9 @@
return card return card
}, },
marketTransactionCard(transactionDetails = {}) { marketTransactionCard(transactionDetails = {}) {
const { buyer, seller, quantity, unitValue, time } = transactionDetails const { buyer, seller, asset, quantity, unitValue, time } = transactionDetails
const card = getRef('market_transaction_template').content.cloneNode(true).firstElementChild const card = getRef('market_transaction_template').content.cloneNode(true).firstElementChild
card.querySelector('.transaction-card__quantity').textContent = `${quantity} FLO` card.querySelector('.transaction-card__quantity').textContent = `${quantity} ${asset}`
card.querySelector('.transaction-card__price').textContent = `₹${unitValue}` card.querySelector('.transaction-card__price').textContent = `₹${unitValue}`
card.querySelector('.transaction-card__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2))) card.querySelector('.transaction-card__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2)))
card.querySelector('.more-info').dataset.time = time card.querySelector('.more-info').dataset.time = time
@ -1047,14 +1048,15 @@
getRef('quantity_type').textContent = tradeType === 'buy' ? `Rupee` : `FLO` getRef('quantity_type').textContent = tradeType === 'buy' ? `Rupee` : `FLO`
}) })
async function tradeFlo() { async function tradeFlo() {
const asset = getRef('get_asset').value;
const quantity = parseFloat(getRef('get_quantity').value) const quantity = parseFloat(getRef('get_quantity').value)
const price = parseFloat(getRef('get_price').value) const price = parseFloat(getRef('get_price').value)
showProcess('trade_button_wrapper') showProcess('trade_button_wrapper')
try { try {
if (tradeType === 'buy') { if (tradeType === 'buy') {
await buy(quantity, price, proxy.userID, await proxy.secret) await buy(asset, quantity, price, proxy.userID, await proxy.secret) //TODO: asset_name
} else { } else {
await sell(quantity, price, proxy.userID, await proxy.secret) await sell(asset, quantity, price, proxy.userID, await proxy.secret) //TODO: asset_name
} }
getRef('trade_button_wrapper').append(getRef('success_template').content.cloneNode(true)) getRef('trade_button_wrapper').append(getRef('success_template').content.cloneNode(true))
notify(`Placed ${tradeType} order`, 'success') notify(`Placed ${tradeType} order`, 'success')
@ -1197,14 +1199,14 @@
if (asset === 'FLO') { if (asset === 'FLO') {
await depositFLO(quantity, proxy.userID, proxy.sinkID, privKey, proxySecret) await depositFLO(quantity, proxy.userID, proxy.sinkID, privKey, proxySecret)
} else { } else {
await depositRupee(quantity, proxy.userID, proxy.sinkID, privKey, proxySecret) await depositToken(quantity, proxy.userID, proxy.sinkID, privKey, proxySecret) //TODO: token_name
} }
showWalletResult('success', `Sent ${asset} deposit request`, 'This may take upto 30 mins to reflect in your wallet.') showWalletResult('success', `Sent ${asset} deposit request`, 'This may take upto 30 mins to reflect in your wallet.')
} else { } else {
if (asset === 'FLO') { if (asset === 'FLO') {
await withdrawFLO(quantity, proxy.userID, proxySecret) await withdrawFLO(quantity, proxy.userID, proxySecret)
} else { } else {
await withdrawRupee(quantity, proxy.userID, proxySecret) await withdrawToken(quantity, proxy.userID, proxySecret) //TODO: token_name
} }
showWalletResult('success', `Sent ${asset} withdraw request`, 'This may take upto 30 mins to reflect in your wallet.') showWalletResult('success', `Sent ${asset} withdraw request`, 'This may take upto 30 mins to reflect in your wallet.')
} }
@ -1422,9 +1424,10 @@
if (ordersType === 'open') { if (ordersType === 'open') {
const allOpenOrders = [...buyOrders, ...sellOrders].sort((a, b) => new Date(b.time_placed).getTime() - new Date(a.time_placed).getTime()) const allOpenOrders = [...buyOrders, ...sellOrders].sort((a, b) => new Date(b.time_placed).getTime() - new Date(a.time_placed).getTime())
allOpenOrders.forEach(order => { allOpenOrders.forEach(order => {
const { id, quantity, minPrice = undefined, maxPrice = undefined, time_placed } = order const { id, asset, quantity, minPrice = undefined, maxPrice = undefined, time_placed } = order
const orderDetails = { const orderDetails = {
id, id,
asset,
quantity, quantity,
type: minPrice ? 'sell' : 'buy', type: minPrice ? 'sell' : 'buy',
price: minPrice || maxPrice, price: minPrice || maxPrice,
@ -1434,7 +1437,7 @@
}) })
} else { } else {
transactions.forEach(transaction => { transactions.forEach(transaction => {
const { quantity, unitValue, tx_time, buyer, seller } = transaction const {asset, quantity, unitValue, tx_time, buyer, seller } = transaction
let type, other; let type, other;
if (seller === proxy.userID) { if (seller === proxy.userID) {
type = 'Sold'; type = 'Sold';
@ -1449,6 +1452,7 @@
seller, seller,
type, type,
other, other,
asset,
quantity, quantity,
unitValue, unitValue,
time: tx_time time: tx_time
@ -1470,9 +1474,10 @@
const [buyOrders, sellOrders] = await Promise.all([getBuyList(), getSellList()]) const [buyOrders, sellOrders] = await Promise.all([getBuyList(), getSellList()])
const allOpenOrders = [...buyOrders, ...sellOrders].sort((a, b) => new Date(b.time_placed).getTime() - new Date(a.time_placed).getTime()) const allOpenOrders = [...buyOrders, ...sellOrders].sort((a, b) => new Date(b.time_placed).getTime() - new Date(a.time_placed).getTime())
allOpenOrders.forEach(order => { allOpenOrders.forEach(order => {
const { floID, quantity, minPrice = undefined, maxPrice = undefined, time_placed } = order const { floID, asset, quantity, minPrice = undefined, maxPrice = undefined, time_placed } = order
const orderDetails = { const orderDetails = {
floID, floID,
asset,
quantity, quantity,
type: minPrice ? 'sell' : 'buy', type: minPrice ? 'sell' : 'buy',
unitValue: minPrice || maxPrice, unitValue: minPrice || maxPrice,
@ -1488,10 +1493,11 @@
try { try {
const marketTransactions = await getTransactionList() const marketTransactions = await getTransactionList()
marketTransactions.forEach(transaction => { marketTransactions.forEach(transaction => {
const { seller, buyer, quantity, unitValue, tx_time } = transaction const { seller, buyer, asset, quantity, unitValue, tx_time } = transaction
const transactionDetails = { const transactionDetails = {
buyer, buyer,
seller, seller,
asset,
quantity, quantity,
unitValue, unitValue,
time: tx_time time: tx_time
@ -1554,14 +1560,14 @@
notify("Password minimum length is 4", 'error'); notify("Password minimum length is 4", 'error');
else { else {
let tmp = Crypto.AES.encrypt(this.private, pwd); let tmp = Crypto.AES.encrypt(this.private, pwd);
localStorage.setItem("proxy_secret", "?" + tmp); localStorage.setItem("exchange-proxy_secret", "?" + tmp);
notify("Successfully locked with Password", 'success'); notify("Successfully locked with Password", 'success');
} }
}).catch(_ => null); }).catch(_ => null);
}, },
clear() { clear() {
localStorage.removeItem("proxy_secret"); localStorage.removeItem("exchange-proxy_secret");
localStorage.removeItem("user_ID"); localStorage.removeItem("exchange-user_ID");
this.user = null; this.user = null;
this.private = null; this.private = null;
this.public = null; this.public = null;
@ -1570,19 +1576,19 @@
return getRef("sink_id").value; return getRef("sink_id").value;
}, },
set userID(id){ set userID(id){
localStorage.setItem("user_ID", id); localStorage.setItem("exchange-user_ID", id);
this.user = id; this.user = id;
}, },
get userID(){ get userID(){
if(this.user) if(this.user)
return this.user; return this.user;
else{ else{
let id = localStorage.getItem('user_ID'); let id = localStorage.getItem('exchange-user_ID');
return id ? this.user = id : undefined; return id ? this.user = id : undefined;
} }
}, },
set secret(key) { set secret(key) {
localStorage.setItem("proxy_secret", key); localStorage.setItem("exchange-proxy_secret", key);
this.private = key; this.private = key;
this.public = floCrypto.getPubKeyHex(key); this.public = floCrypto.getPubKeyHex(key);
}, },
@ -1605,7 +1611,7 @@
Reject("Unable to fetch Proxy secret"); Reject("Unable to fetch Proxy secret");
} }
}; };
let tmp = localStorage.getItem("proxy_secret"); let tmp = localStorage.getItem("exchange-proxy_secret");
if (typeof tmp !== "string") if (typeof tmp !== "string")
Reject("Unable to fetch Proxy secret"); Reject("Unable to fetch Proxy secret");
else if (tmp.startsWith("?")) { else if (tmp.startsWith("?")) {
@ -1629,11 +1635,21 @@
} }
let floExchangeRate = 0 let floExchangeRate = 0
function updateRate() { function updateRate(init = false) {
getRate().then(rate => { getRates().then(rates => {
floExchangeRate = parseFloat(rate) console.debug(rates);
getRef('flo_rate').textContent = formatAmount(parseFloat(rate)) if(init){
getRef('get_price').value = parseFloat(parseFloat(rate).toFixed(2)) let assetList = getRef('get_asset');
for(let asset in rates){
let e = document.createElement('option');
e.innerText = asset;
assetList.appendChild(e);
}
}
let flo_rate = rates["FLO"];
floExchangeRate = parseFloat(flo_rate)
getRef('flo_rate').textContent = formatAmount(parseFloat(flo_rate))
getRef('get_price').value = parseFloat(parseFloat(flo_rate).toFixed(2))
}).catch(error => console.error(error)) }).catch(error => console.error(error))
} }
@ -1652,7 +1668,7 @@
} }
} else } else
console.info("refresh"); console.info("refresh");
updateRate(); updateRate(init);
renderMarketOrders(); renderMarketOrders();
if(proxy.userID) if(proxy.userID)
account(); account();
@ -1686,7 +1702,8 @@
getRef("user_id").value = acc.floID; getRef("user_id").value = acc.floID;
getRef("sink_id").value = acc.sinkID; getRef("sink_id").value = acc.sinkID;
//FLO Balance //FLO Balance
let flo_total = acc.coins.reduce((a, x) => a + x.quantity, 0); console.debug(acc.vault);
let flo_total = acc.vault.reduce((a, x) => a + (x.asset === "FLO" ? x.quantity : 0), 0);
let flo_locked = acc.sellOrders.reduce((a, x) => a + x.quantity, 0); let flo_locked = acc.sellOrders.reduce((a, x) => a + x.quantity, 0);
let flo_net = flo_total - flo_locked; let flo_net = flo_total - flo_locked;
console.debug("FLO", flo_total, flo_locked, flo_net); console.debug("FLO", flo_total, flo_locked, flo_net);
@ -1694,7 +1711,7 @@
showBalance("flo", flo_net, flo_locked,) showBalance("flo", flo_net, flo_locked,)
//Rupee Balance //Rupee Balance
let rupee_total = acc.rupee_total; let rupee_total = acc.cash;
let rupee_locked = acc.buyOrders.reduce((a, x) => a + x.quantity * x.maxPrice, 0); let rupee_locked = acc.buyOrders.reduce((a, x) => a + x.quantity * x.maxPrice, 0);
let rupee_net = rupee_total - rupee_locked; let rupee_net = rupee_total - rupee_locked;
console.debug("RUPEE", rupee_total, rupee_locked, rupee_net); console.debug("RUPEE", rupee_total, rupee_locked, rupee_net);

View File

@ -4,7 +4,7 @@ const express = require('express');
//const sessions = require('express-session'); //const sessions = require('express-session');
const Request = require('./request'); const Request = require('./request');
const REFRESH_INTERVAL = 5 * 1000; //10 * 60 * 1000; const REFRESH_INTERVAL = 1 * 60 * 1000;
module.exports = function App(secret, DB) { module.exports = function App(secret, DB) {
@ -72,7 +72,7 @@ module.exports = function App(secret, DB) {
//list all process transactions and rate //list all process transactions and rate
app.get('/list-transactions', Request.ListTransactions); app.get('/list-transactions', Request.ListTransactions);
app.get('/get-rate', Request.getRate) app.get('/get-rates', Request.getRates)
//get account details //get account details
app.post('/account', Request.Account); app.post('/account', Request.Account);
@ -80,8 +80,8 @@ module.exports = function App(secret, DB) {
//withdraw and deposit request //withdraw and deposit request
app.post('/deposit-flo', Request.DepositFLO); app.post('/deposit-flo', Request.DepositFLO);
app.post('/withdraw-flo', Request.WithdrawFLO); app.post('/withdraw-flo', Request.WithdrawFLO);
app.post('/deposit-rupee', Request.DepositRupee); app.post('/deposit-token', Request.DepositToken);
app.post('/withdraw-rupee', Request.WithdrawRupee); app.post('/withdraw-token', Request.WithdrawToken);
//Manage user tags (Access to trusted IDs only) //Manage user tags (Access to trusted IDs only)
@ -108,6 +108,10 @@ module.exports = function App(secret, DB) {
set: (ids) => Request.trustedIDs = ids set: (ids) => Request.trustedIDs = ids
}); });
Object.defineProperty(self, "assetList", {
set: (assets) => Request.assetList = assets
});
//Start (or) Stop servers //Start (or) Stop servers
self.start = (port) => new Promise(resolve => { self.start = (port) => new Promise(resolve => {
server = app.listen(port, () => { server = app.listen(port, () => {

View File

@ -5,7 +5,7 @@ const slave = require('./slave');
const WebSocket = require('ws'); const WebSocket = require('ws');
const shareThreshold = 50 / 100; const shareThreshold = 50 / 100;
var DB, app, wss; //Container for database and app var DB, app, wss, tokenList; //Container for database and app
var nodeList, nodeURL, nodeKBucket; //Container for (backup) node list var nodeList, nodeURL, nodeKBucket; //Container for (backup) node list
var nodeShares = null, var nodeShares = null,
nodeSinkID = null, nodeSinkID = null,
@ -104,8 +104,8 @@ function send_dataImmutable(timestamp, ws) {
const immutable_tables = { const immutable_tables = {
Users: "created", Users: "created",
Request_Log: "request_time", Request_Log: "request_time",
Transactions: "tx_time", TransactionHistory: "tx_time",
priceHistory: "rec_time" PriceHistory: "rec_time"
}; };
const sendTable = (table, timeCol) => new Promise((res, rej) => { const sendTable = (table, timeCol) => new Promise((res, rej) => {
DB.query(`SELECT * FROM ${table} WHERE ${timeCol} > ?`, [timestamp]) DB.query(`SELECT * FROM ${table} WHERE ${timeCol} > ?`, [timestamp])
@ -175,16 +175,36 @@ function storeSink(sinkID, sinkPrivKey) {
.catch(error => console.error(error)); .catch(error => console.error(error));
} }
function transferMoneyToNewSink(oldSinkID, oldSinkKey) { function transferMoneyToNewSink(oldSinkID, oldSinkKey, newSink) {
const transferToken = token => new Promise((resolve, reject) => {
tokenAPI.getBalance(oldSinkID, token).then(tokenBalance => {
floBlockchainAPI.writeData(oldSinkID, `send ${tokenBalance} ${token}# |Exchange-market New sink`, oldSinkKey, newSink.floID, false)
.then(txid => resolve(txid))
.catch(error => reject(error))
})
});
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let newSink = generateNewSink(); console.debug("Transferring tokens to new Sink:", newSink.floID)
floBlockchainAPI.getBalance(oldSinkID).then(balFLO => { Promise.allSettled(tokenList.map(token => transferToken(token))).then(result => {
tokenAPI.getBalance(oldSinkID).then(balRupee => { let failedFlag = false;
floBlockchainAPI.sendTx(oldSinkID, newSink.floID, balFLO - floGlobals.fee, oldSinkKey, `send ${balRupee} ${floGlobals.token}# |Exchange-market New sink`) tokenList.forEach((token, i) => {
.then(result => resolve(newSink)) if (result[i].status === "fulfilled")
.catch(error => reject(error)) console.log(token, result[i].value);
}).catch(error => reject(error)); else {
}).catch(error => reject(error)) failedFlag = true;
console.error(token, result[i].reason);
}
});
if (failedFlag)
return reject("Some token transfer has failed");
floBlockchainAPI.getBalance(oldSinkID).then(floBalance => {
tokenAPI.getBalance(oldSinkID).then(cashBalance => {
floBlockchainAPI.sendTx(oldSinkID, newSink.floID, floBalance - floGlobals.fee, oldSinkKey, `send ${cashBalance} ${floGlobals.currency}# |Exchange-market New sink`)
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error));
}).catch(error => reject(error))
});
}) })
} }
@ -196,15 +216,17 @@ function collectShares(floID, sinkID, share) {
return console.error("Something is wrong! Slaves are sending different sinkID"); return console.error("Something is wrong! Slaves are sending different sinkID");
collectShares.shares[floID] = share; collectShares.shares[floID] = share;
try { try {
let privKey = floCrypto.retrieveShamirSecret(Object.values(collectShares.shares)); let oldSinkKey = floCrypto.retrieveShamirSecret(Object.values(collectShares.shares));
if (floCrypto.verifyPrivKey(privKey, collectShares.sinkID)) { if (floCrypto.verifyPrivKey(oldSinkKey, collectShares.sinkID)) {
transferMoneyToNewSink(collectShares.sinkID, privKey).then(newSink => { let newSink = generateNewSink();
delete collectShares.sinkID; transferMoneyToNewSink(collectShares.sinkID, oldSinkKey, newSink).then(result => {
delete collectShares.shares; console.log("Money transfer successful", result);
collectShares.active = false; delete collectShares.sinkID;
storeSink(newSink.floID, newSink.privKey); delete collectShares.shares;
sendSharesToNodes(newSink.floID, newSink.shares); collectShares.active = false;
}).catch(error => console.error(error)); sendSharesToNodes(newSink.floID, newSink.shares);
}).catch(error => console.error(error))
.finally(_ => storeSink(newSink.floID, newSink.privKey));
} }
} catch (error) { } catch (error) {
//Unable to retrive sink private key. Waiting for more shares! Do nothing for now //Unable to retrive sink private key. Waiting for more shares! Do nothing for now
@ -391,6 +413,9 @@ module.exports = {
nodeList = nodeKBucket.order; nodeList = nodeKBucket.order;
console.debug(nodeList); console.debug(nodeList);
}, },
set assetList(assets) {
tokenList = assets.filter(a => a.toUpperCase() !== "FLO");
},
set DB(db) { set DB(db) {
DB = db; DB = db;
slave.DB = db; slave.DB = db;

View File

@ -32,6 +32,7 @@ function stopSlaveProcess() {
if (masterWS !== null) { if (masterWS !== null) {
masterWS.onclose = () => null; masterWS.onclose = () => null;
masterWS.close(); masterWS.close();
requestInstance.close();
masterWS = null; masterWS = null;
} }
if (intervalID !== null) { if (intervalID !== null) {
@ -45,8 +46,8 @@ function requestBackupSync(ws) {
const tables = { const tables = {
Users: "created", Users: "created",
Request_Log: "request_time", Request_Log: "request_time",
Transactions: "tx_time", TransactionHistory: "tx_time",
//priceHistory: "rec_time", //PriceHistory: "rec_time",
_backup: "timestamp" _backup: "timestamp"
}; };
let subs = []; let subs = [];
@ -161,6 +162,9 @@ function sendSinkShare() {
} }
function processBackupData(response) { function processBackupData(response) {
//TODO: Sync improvements needed. (2 types)
//1. Either sync has to be completed or rollback all
//2. Each table/data should be treated as independent chunks
const self = requestInstance; const self = requestInstance;
self.last_response_time = Date.now(); self.last_response_time = Date.now();
switch (response.command) { switch (response.command) {

View File

@ -5,9 +5,9 @@ const price = require("./price");
var DB; //container for database var DB; //container for database
function initiate() { function startCouplingForAsset(asset) {
price.getRates().then(cur_rate => { price.getRates(asset).then(cur_rate => {
group.getBestPairs(cur_rate) group.getBestPairs(asset, cur_rate)
.then(bestPairQueue => processCoupling(bestPairQueue)) .then(bestPairQueue => processCoupling(bestPairQueue))
.catch(error => console.error("initiateCoupling", error)) .catch(error => console.error("initiateCoupling", error))
}).catch(error => console.error(error)); }).catch(error => console.error(error));
@ -19,17 +19,21 @@ function processCoupling(bestPairQueue) {
seller_best = pair_result.sellOrder; seller_best = pair_result.sellOrder;
console.debug("Sell:", seller_best); console.debug("Sell:", seller_best);
console.debug("Buy:", buyer_best); console.debug("Buy:", buyer_best);
spendFLO(buyer_best, seller_best, pair_result.null_base).then(spend_result => { spendAsset(bestPairQueue.asset, buyer_best, seller_best, pair_result.null_base).then(spent => {
let tx_quantity = spend_result.quantity, if (!spent.quantity) {
txQueries = spend_result.txQueries, //Happens when there are only Null-base assets
clear_sell = spend_result.incomplete && !spend_result.flag_baseNull; //clear_sell can be true only if an order is placed without enough FLO bestPairQueue.next(spent.quantity, spent.incomplete);
processOrders(seller_best, buyer_best, txQueries, tx_quantity, clear_sell); processCoupling(bestPairQueue);
updateBalance(seller_best, buyer_best, txQueries, bestPairQueue.cur_rate, tx_quantity); 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 //begin audit
beginAudit(seller_best.floID, buyer_best.floID, bestPairQueue.cur_rate, tx_quantity).then(audit => { beginAudit(seller_best.floID, buyer_best.floID, bestPairQueue.asset, bestPairQueue.cur_rate, spent.quantity).then(audit => {
//process txn query in SQL //process txn query in SQL
DB.transaction(txQueries).then(_ => { DB.transaction(txQueries).then(_ => {
bestPairQueue.next(tx_quantity, spend_result.incomplete, spend_result.flag_baseNull); bestPairQueue.next(spent.quantity, spent.incomplete);
console.log(`Transaction was successful! BuyOrder:${buyer_best.id}| SellOrder:${seller_best.id}`); console.log(`Transaction was successful! BuyOrder:${buyer_best.id}| SellOrder:${seller_best.id}`);
audit.end(); audit.end();
price.updateLastTime(); price.updateLastTime();
@ -46,7 +50,7 @@ function processCoupling(bestPairQueue) {
console.error(error.buy); console.error(error.buy);
noBuy = null; noBuy = null;
} else { } else {
console.log("No valid buyOrders."); console.log("No valid buyOrders for Asset:", bestPairQueue.asset);
noBuy = true; noBuy = true;
} }
if (error.sell === undefined) if (error.sell === undefined)
@ -55,35 +59,31 @@ function processCoupling(bestPairQueue) {
console.error(error.sell); console.error(error.sell);
noSell = null; noSell = null;
} else { } else {
console.log("No valid sellOrders."); console.log("No valid sellOrders for Asset:", bestPairQueue.asset);
noSell = true; noSell = true;
} }
price.noOrder(noBuy, noSell); price.noOrder(bestPairQueue.asset, noBuy, noSell);
}); });
} }
function spendFLO(buyOrder, sellOrder, null_base) { function spendAsset(asset, buyOrder, sellOrder, null_base) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY base", [sellOrder.floID]).then(result => { 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), let rem = Math.min(buyOrder.quantity, sellOrder.quantity),
txQueries = [], txQueries = [];
flag_baseNull = false;
for (let i = 0; i < result.length && rem > 0; i++) for (let i = 0; i < result.length && rem > 0; i++)
if (result[i].base || null_base) { if (rem < result[i].quantity) {
if (rem < result[i].quantity) { txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]);
txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]); rem = 0;
rem = 0; } else {
} else { txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]);
txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]); rem -= result[i].quantity;
rem -= result[i].quantity; }
}
} else
flag_baseNull = true;
resolve({ resolve({
quantity: Math.min(buyOrder.quantity, sellOrder.quantity) - rem, quantity: Math.min(buyOrder.quantity, sellOrder.quantity) - rem,
txQueries, txQueries,
incomplete: rem > 0, incomplete: rem > 0
flag_baseNull
}); });
}).catch(error => reject(error)); }).catch(error => reject(error));
}) })
@ -98,55 +98,56 @@ 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) if (quantity == seller_best.quantity || clear_sell) //clear_sell must be true iff an order is placed without enough Asset
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]]);
} }
function updateBalance(seller_best, buyer_best, txQueries, cur_price, quantity) { function updateBalance(seller_best, buyer_best, txQueries, asset, cur_price, quantity) {
//Update rupee balance for seller and buyer //Update cash balance for seller and buyer
let totalAmount = cur_price * quantity; let totalAmount = cur_price * quantity;
txQueries.push(["UPDATE Cash SET rupeeBalance=rupeeBalance+? WHERE floID=?", [totalAmount, seller_best.floID]]); txQueries.push(["UPDATE Cash SET balance=balance+? WHERE floID=?", [totalAmount, seller_best.floID]]);
txQueries.push(["UPDATE Cash SET rupeeBalance=rupeeBalance-? WHERE floID=?", [totalAmount, buyer_best.floID]]); txQueries.push(["UPDATE Cash SET balance=balance-? WHERE floID=?", [totalAmount, buyer_best.floID]]);
//Add coins to Buyer //Add coins to Buyer
txQueries.push(["INSERT INTO Vault(floID, base, quantity) VALUES (?, ?, ?)", [buyer_best.floID, cur_price, quantity]]) txQueries.push(["INSERT INTO Vault(floID, asset, base, quantity) VALUES (?, ?, ?, ?)", [buyer_best.floID, asset, cur_price, quantity]])
//Record transaction //Record transaction
txQueries.push(["INSERT INTO Transactions (seller, buyer, quantity, unitValue) VALUES (?, ?, ?, ?)", [seller_best.floID, buyer_best.floID, quantity, cur_price]]); txQueries.push(["INSERT INTO TransactionHistory (seller, buyer, asset, quantity, unitValue) VALUES (?, ?, ?, ?, ?)", [seller_best.floID, buyer_best.floID, asset, quantity, cur_price]]);
} }
function beginAudit(sellerID, buyerID, unit_price, quantity) { function beginAudit(sellerID, buyerID, asset, unit_price, quantity) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
auditBalance(sellerID, buyerID).then(old_bal => resolve({ auditBalance(sellerID, buyerID, asset).then(old_bal => resolve({
end: () => endAudit(sellerID, buyerID, old_bal, unit_price, quantity) end: () => endAudit(sellerID, buyerID, asset, old_bal, unit_price, quantity)
})).catch(error => reject(error)) })).catch(error => reject(error))
}) })
} }
function endAudit(sellerID, buyerID, old_bal, unit_price, quantity) { function endAudit(sellerID, buyerID, asset, old_bal, unit_price, quantity) {
auditBalance(sellerID, buyerID).then(new_bal => { auditBalance(sellerID, buyerID, asset).then(new_bal => {
DB.query("INSERT INTO auditTransaction (sellerID, buyerID, quantity, unit_price, total_cost, " + DB.query("INSERT INTO AuditTransaction (asset, quantity, unit_price, total_cost," +
" Rupee_seller_old, Rupee_seller_new, Rupee_buyer_old, Rupee_buyer_new," + " sellerID, seller_old_cash, seller_old_asset, seller_new_cash, seller_new_asset," +
" FLO_seller_old, FLO_seller_new, FLO_buyer_old, FLO_buyer_new) " + " buyerID, buyer_old_cash, buyer_old_asset, buyer_new_cash, buyer_new_asset)" +
" Value (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [sellerID, buyerID, quantity, unit_price, quantity * unit_price, " Value (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [
old_bal[sellerID].Rupee, new_bal[sellerID].Rupee, old_bal[buyerID].Rupee, new_bal[buyerID].Rupee, asset, quantity, unit_price, quantity * unit_price,
old_bal[sellerID].FLO, new_bal[sellerID].FLO, old_bal[buyerID].FLO, new_bal[buyerID].FLO, sellerID, old_bal[sellerID].cash, old_bal[sellerID].asset, new_bal[sellerID].cash, new_bal[sellerID].asset,
buyerID, old_bal[buyerID].cash, old_bal[buyerID].asset, new_bal[buyerID].cash, new_bal[buyerID].asset,
]).then(_ => null).catch(error => console.error(error)) ]).then(_ => null).catch(error => console.error(error))
}).catch(error => console.error(error)); }).catch(error => console.error(error));
} }
function auditBalance(sellerID, buyerID) { function auditBalance(sellerID, buyerID, asset) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let balance = { let balance = {
[sellerID]: {}, [sellerID]: {},
[buyerID]: {} [buyerID]: {}
}; };
DB.query("SELECT floID, rupeeBalance FROM Cash WHERE floID IN (?, ?)", [sellerID, buyerID]).then(result => { DB.query("SELECT floID, balance FROM Cash WHERE floID IN (?, ?)", [sellerID, buyerID]).then(result => {
for (let i in result) for (let i in result)
balance[result[i].floID].Rupee = result[i].rupeeBalance; balance[result[i].floID].cash = result[i].balance;
DB.query("SELECT floID, SUM(quantity) as floBal FROM Vault WHERE floID IN (?, ?) GROUP BY floID", [sellerID, buyerID]).then(result => { 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) for (let i in result)
balance[result[i].floID].FLO = result[i].floBal; balance[result[i].floID].asset = result[i].asset_balance;
resolve(balance); resolve(balance);
}).catch(error => reject(error)) }).catch(error => reject(error))
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -154,8 +155,11 @@ function auditBalance(sellerID, buyerID) {
} }
module.exports = { module.exports = {
initiate, initiate: startCouplingForAsset,
group, group: {
addTag: group.addTag,
removeTag: group.removeTag
},
price, price,
set DB(db) { set DB(db) {
DB = db; DB = db;

View File

@ -4,7 +4,7 @@ var DB; //container for database
function addTag(floID, tag) { function addTag(floID, tag) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("INSERT INTO Tags (floID, tag) VALUE (?,?)", [floID, tag]) DB.query("INSERT INTO UserTag (floID, tag) VALUE (?,?)", [floID, tag])
.then(result => resolve(`Added ${floID} to ${tag}`)) .then(result => resolve(`Added ${floID} to ${tag}`))
.catch(error => { .catch(error => {
if (error.code === "ER_DUP_ENTRY") if (error.code === "ER_DUP_ENTRY")
@ -19,28 +19,31 @@ function addTag(floID, tag) {
function removeTag(floID, tag) { function removeTag(floID, tag) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("DELETE FROM Tags WHERE floID=? AND tag=?", [floID, tag]) DB.query("DELETE FROM UserTag WHERE floID=? AND tag=?", [floID, tag])
.then(result => resolve(`Removed ${floID} from ${tag}`)) .then(result => resolve(`Removed ${floID} from ${tag}`))
.catch(error => reject(error)); .catch(error => reject(error));
}) })
} }
function getBestPairs(currentRate) { function getBestPairs(asset, cur_rate) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT tag, sellPriority, buyPriority FROM TagList").then(result => { DB.query("SELECT tag, sellPriority, buyPriority FROM TagList").then(result => {
//Sorted in Ascending (ie, stack; pop for highest) //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_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); let tags_sell = result.sort((a, b) => a.sellPriority > b.sellPriority ? 1 : -1).map(r => r.tag);
resolve(new bestPair(currentRate, tags_buy, tags_sell)); resolve(new bestPair(asset, cur_rate, tags_buy, tags_sell));
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
} }
const bestPair = function(cur_rate, tags_buy, tags_sell) { const bestPair = function(asset, cur_rate, tags_buy, tags_sell) {
const currentRate = cur_rate;
Object.defineProperty(this, 'asset', {
get: () => asset
});
Object.defineProperty(this, 'cur_rate', { Object.defineProperty(this, 'cur_rate', {
get: () => currentRate get: () => cur_rate,
}); });
this.get = () => new Promise((resolve, reject) => { this.get = () => new Promise((resolve, reject) => {
@ -59,7 +62,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
}).catch(error => reject(error)) }).catch(error => reject(error))
}); });
this.next = (tx_quantity, incomplete_sell, flag_sell) => { this.next = (tx_quantity, incomplete_sell) => {
let buy = getBuyOrder.cache, let buy = getBuyOrder.cache,
sell = getSellOrder.cache; sell = getSellOrder.cache;
if (buy.cur_order && sell.cur_order) { if (buy.cur_order && sell.cur_order) {
@ -74,7 +77,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
if (tx_quantity < sell.cur_order.quantity) { if (tx_quantity < sell.cur_order.quantity) {
sell.cur_order.quantity -= tx_quantity; sell.cur_order.quantity -= tx_quantity;
if (incomplete_sell) { if (incomplete_sell) {
if (!sell.mode_null && flag_sell) if (!sell.mode_null)
sell.null_queue.push(sell.cur_order); sell.null_queue.push(sell.cur_order);
sell.cur_order = null; sell.cur_order = null;
} }
@ -89,7 +92,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
const getSellOrder = () => new Promise((resolve, reject) => { const getSellOrder = () => new Promise((resolve, reject) => {
let cache = getSellOrder.cache; let cache = getSellOrder.cache;
if (cache.cur_order) { //If cache already has a pending order if (cache.cur_order) { //If cache already has a pending order
verifySellOrder(cache.cur_order, currentRate, cache.mode_null).then(result => { verifySellOrder(cache.cur_order, asset, cur_rate, cache.mode_null).then(result => {
cache.cur_order = result; cache.cur_order = result;
resolve(result); resolve(result);
}).catch(error => { }).catch(error => {
@ -102,7 +105,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
.catch(error => reject(error)) .catch(error => reject(error))
}) })
} else if (cache.orders && cache.orders.length) { //If cache already has orders in priority } else if (cache.orders && cache.orders.length) { //If cache already has orders in priority
getTopValidSellOrder(cache.orders, currentRate, cache.mode_null).then(result => { getTopValidSellOrder(cache.orders, asset, cur_rate, cache.mode_null).then(result => {
cache.cur_order = result; cache.cur_order = result;
resolve(result); resolve(result);
}).catch(error => { }).catch(error => {
@ -116,14 +119,14 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
}) })
} else if (cache.tags.length) { //If cache has remaining tags } else if (cache.tags.length) { //If cache has remaining tags
cache.cur_tag = cache.tags.pop(); cache.cur_tag = cache.tags.pop();
getSellOrdersInTag(cache.cur_tag, currentRate).then(orders => { getSellOrdersInTag(cache.cur_tag, asset, cur_rate).then(orders => {
cache.orders = orders; cache.orders = orders;
getSellOrder() getSellOrder()
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)) .catch(error => reject(error))
}).catch(error => reject(error)); }).catch(error => reject(error));
} else if (!cache.end) { //Un-tagged floID's orders (do only once) } else if (!cache.end) { //Un-tagged floID's orders (do only once)
getUntaggedSellOrders(currentRate).then(orders => { getUntaggedSellOrders(asset, cur_rate).then(orders => {
cache.orders = orders; cache.orders = orders;
cache.cur_tag = null; cache.cur_tag = null;
cache.end = true; cache.end = true;
@ -131,7 +134,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)) .catch(error => reject(error))
}).catch(error => reject(error)); }).catch(error => reject(error));
} else if (!cache.mode_null) { //Lowest priority Coins (FLO Brought from other sources) } 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.orders = cache.null_queue.reverse(); //Reverse it so that we can pop the highest priority
cache.mode_null = true; cache.mode_null = true;
cache.null_queue = null; cache.null_queue = null;
@ -150,7 +153,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
const getBuyOrder = () => new Promise((resolve, reject) => { const getBuyOrder = () => new Promise((resolve, reject) => {
let cache = getBuyOrder.cache; let cache = getBuyOrder.cache;
if (cache.cur_order) { //If cache already has a pending order if (cache.cur_order) { //If cache already has a pending order
verifyBuyOrder(cache.cur_order, currentRate).then(result => { verifyBuyOrder(cache.cur_order, cur_rate).then(result => {
cache.cur_order = result; cache.cur_order = result;
resolve(result); resolve(result);
}).catch(error => { }).catch(error => {
@ -163,7 +166,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
.catch(error => reject(error)) .catch(error => reject(error))
}) })
} else if (cache.orders && cache.orders.length) { //If cache already has orders in priority } else if (cache.orders && cache.orders.length) { //If cache already has orders in priority
getTopValidBuyOrder(cache.orders, currentRate).then(result => { getTopValidBuyOrder(cache.orders, cur_rate).then(result => {
cache.cur_order = result; cache.cur_order = result;
resolve(result); resolve(result);
}).catch(error => { }).catch(error => {
@ -177,14 +180,14 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
}) })
} else if (cache.tags.length) { //If cache has remaining tags } else if (cache.tags.length) { //If cache has remaining tags
cache.cur_tag = cache.tags.pop(); cache.cur_tag = cache.tags.pop();
getBuyOrdersInTag(cache.cur_tag, currentRate).then(orders => { getBuyOrdersInTag(cache.cur_tag, asset, cur_rate).then(orders => {
cache.orders = orders; cache.orders = orders;
getBuyOrder() getBuyOrder()
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)) .catch(error => reject(error))
}).catch(error => reject(error)); }).catch(error => reject(error));
} else if (!cache.end) { //Un-tagged floID's orders (do only once) } else if (!cache.end) { //Un-tagged floID's orders (do only once)
getUntaggedBuyOrders(currentRate).then(orders => { getUntaggedBuyOrders(asset, cur_rate).then(orders => {
cache.orders = orders; cache.orders = orders;
cache.cur_tag = null; cache.cur_tag = null;
cache.end = true; cache.end = true;
@ -200,31 +203,34 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
}; };
} }
function getUntaggedSellOrders(cur_price) { function getUntaggedSellOrders(asset, cur_price) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity FROM SellOrder" + DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity FROM SellOrder" +
" LEFT JOIN Tags ON Tags.floID = SellOrder.floID" + " LEFT JOIN UserTag ON UserTag.floID = SellOrder.floID" +
" WHERE Tags.floID IS NULL AND SellOrder.minPrice <=? ORDER BY SellOrder.time_placed DESC", [cur_price]) " WHERE UserTag.floID IS NULL AND SellOrder.asset = ? AND SellOrder.minPrice <=?" +
" ORDER BY SellOrder.time_placed DESC", [asset, cur_price])
.then(orders => resolve(orders)) .then(orders => resolve(orders))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
} }
function getUntaggedBuyOrders(cur_price) { function getUntaggedBuyOrders(asset, cur_price) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" + DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" +
" LEFT JOIN Tags ON Tags.floID = BuyOrder.floID" + " LEFT JOIN UserTag ON UserTag.floID = BuyOrder.floID" +
" WHERE Tags.floID IS NULL AND BuyOrder.maxPrice >=? ORDER BY BuyOrder.time_placed DESC", [cur_price]) " WHERE UserTag.floID IS NULL AND BuyOrder.asset = ? AND BuyOrder.maxPrice >=? " +
" ORDER BY BuyOrder.time_placed DESC", [asset, cur_price])
.then(orders => resolve(orders)) .then(orders => resolve(orders))
.catch(error => reject(error)) .catch(error => reject(error))
}) })
} }
function getSellOrdersInTag(tag, cur_price) { function getSellOrdersInTag(tag, asset, cur_price) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity FROM SellOrder" + DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity FROM SellOrder" +
" INNER JOIN Tags ON Tags.floID = SellOrder.floID" + " INNER JOIN UserTag ON UserTag.floID = SellOrder.floID" +
" WHERE Tags.tag = ? AND SellOrder.minPrice <=? ORDER BY SellOrder.time_placed DESC", [tag, cur_price]).then(orders => { " WHERE UserTag.tag = ? AND SellOrder.asset = ? AND SellOrder.minPrice <=?" +
" ORDER BY SellOrder.time_placed DESC", [tag, asset, cur_price]).then(orders => {
if (orders.length <= 1) // No (or) Only-one order, hence priority sort not required. if (orders.length <= 1) // No (or) Only-one order, hence priority sort not required.
resolve(orders); resolve(orders);
else else
@ -238,11 +244,12 @@ function getSellOrdersInTag(tag, cur_price) {
}); });
} }
function getBuyOrdersInTag(tag, cur_price) { function getBuyOrdersInTag(tag, asset, cur_price) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" + DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" +
" INNER JOIN Tags ON Tags.floID = BuyOrder.floID" + " INNER JOIN UserTag ON UserTag.floID = BuyOrder.floID" +
" WHERE Tags.tag = ? AND BuyOrder.maxPrice >=? ORDER BY BuyOrder.time_placed DESC", [tag, cur_price]).then(orders => { " WHERE UserTag.tag = ? AND BuyOrder.asset = ? AND BuyOrder.maxPrice >=?" +
" ORDER BY BuyOrder.time_placed DESC", [tag, asset, cur_price]).then(orders => {
if (orders.length <= 1) // No (or) Only-one order, hence priority sort not required. if (orders.length <= 1) // No (or) Only-one order, hence priority sort not required.
resolve(orders); resolve(orders);
else else
@ -287,26 +294,26 @@ function fetch_api(api, id) {
}) })
} }
function getTopValidSellOrder(orders, cur_price, mode_null) { function getTopValidSellOrder(orders, asset, cur_price, mode_null) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!orders.length) if (!orders.length)
return reject(false) return reject(false)
verifySellOrder(orders.pop(), cur_price, mode_null) //pop: as the orders are sorted in ascending (highest point should be checked 1st) 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)) .then(result => resolve(result))
.catch(error => { .catch(error => {
if (error !== false) if (error !== false)
return reject(error); return reject(error);
getTopValidSellOrder(orders, cur_price, mode_null) getTopValidSellOrder(orders, asset, cur_price, mode_null)
.then(result => resolve(result)) .then(result => resolve(result))
.catch(error => reject(error)); .catch(error => reject(error));
}); });
}); });
} }
function verifySellOrder(sellOrder, cur_price, mode_null) { function verifySellOrder(sellOrder, asset, cur_price, mode_null) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!mode_null) if (!mode_null)
DB.query("SELECT quantity, base FROM Vault WHERE floID=? AND base IS NOT NULL ORDER BY base", [sellOrder.floID]).then(result => { 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, let rem = sellOrder.quantity,
sell_base = 0, sell_base = 0,
base_quantity = 0; base_quantity = 0;
@ -329,10 +336,10 @@ function verifySellOrder(sellOrder, cur_price, mode_null) {
resolve(sellOrder); resolve(sellOrder);
}).catch(error => reject(error)); }).catch(error => reject(error));
else if (mode_null) else if (mode_null)
DB.query("SELECT SUM(quantity) as total FROM Vault WHERE floID=?", [sellOrder.floID]).then(result => { DB.query("SELECT SUM(quantity) as total FROM Vault WHERE floID=? AND asset=?", [sellOrder.floID, asset]).then(result => {
if (result.total < sellOrder.quantity) if (result[0].total < sellOrder.quantity)
console.warn(`Sell Order ${sellOrder.id} was made without enough FLO. This should not happen`); console.warn(`Sell Order ${sellOrder.id} was made without enough Assets. This should not happen`);
if (result.total > 0) if (result[0].total > 0)
resolve(sellOrder); resolve(sellOrder);
else else
reject(false); reject(false);
@ -358,10 +365,10 @@ function getTopValidBuyOrder(orders, cur_price) {
function verifyBuyOrder(buyOrder, cur_price) { function verifyBuyOrder(buyOrder, cur_price) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT rupeeBalance AS bal FROM Cash WHERE floID=?", [buyOrder.floID]).then(result => { DB.query("SELECT balance AS bal FROM Cash WHERE floID=?", [buyOrder.floID]).then(result => {
if (result[0].bal < cur_price * buyOrder.quantity) { if (result[0].bal < cur_price * buyOrder.quantity) {
//This should not happen unless a buy order is placed when user doesnt have enough rupee balance //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 rupee# is insufficient`); console.warn(`Buy order ${buyOrder.id} is active, but Cash is insufficient`);
reject(false); reject(false);
} else } else
resolve(buyOrder); resolve(buyOrder);

View File

@ -25,7 +25,7 @@ function refreshData(startup = false) {
function refreshDataFromBlockchain() { function refreshDataFromBlockchain() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT num FROM lastTx WHERE floID=?", [floGlobals.adminID]).then(result => { DB.query("SELECT num FROM LastTx WHERE floID=?", [floGlobals.adminID]).then(result => {
let lastTx = result.length ? result[0].num : 0; let lastTx = result.length ? result[0].num : 0;
floBlockchainAPI.readData(floGlobals.adminID, { floBlockchainAPI.readData(floGlobals.adminID, {
ignoreOld: lastTx, ignoreOld: lastTx,
@ -34,6 +34,7 @@ function refreshDataFromBlockchain() {
}).then(result => { }).then(result => {
let promises = [], let promises = [],
nodes_change = false, nodes_change = false,
assets_change = false,
trusted_change = false; trusted_change = false;
result.data.reverse().forEach(data => { result.data.reverse().forEach(data => {
var content = JSON.parse(data)[floGlobals.application]; var content = JSON.parse(data)[floGlobals.application];
@ -42,20 +43,26 @@ function refreshDataFromBlockchain() {
nodes_change = true; nodes_change = true;
if (content.Nodes.remove) if (content.Nodes.remove)
for (let n of content.Nodes.remove) for (let n of content.Nodes.remove)
promises.push(DB.query("DELETE FROM nodeList WHERE floID=?", [n])); promises.push(DB.query("DELETE FROM NodeList WHERE floID=?", [n]));
if (content.Nodes.add) if (content.Nodes.add)
for (let n in content.Nodes.add) for (let n in content.Nodes.add)
promises.push(DB.query("INSERT INTO nodeList (floID, uri) VALUE (?,?) AS new ON DUPLICATE KEY UPDATE uri=new.uri", [n, content.Nodes.add[n]])); promises.push(DB.query("INSERT INTO NodeList (floID, uri) VALUE (?,?) AS new ON DUPLICATE KEY UPDATE uri=new.uri", [n, content.Nodes.add[n]]));
}
//Asset List
if (content.Assets) {
assets_change = true;
for (let a in content.Assets)
promises.push(DB.query("INSERT INTO AssetList (asset, initialPrice) VALUE (?,?) AS new ON DUPLICATE KEY UPDATE initialPrice=new.initialPrice", [a, content.Assets[a]]));
} }
//Trusted List //Trusted List
if (content.Trusted) { if (content.Trusted) {
trusted_change = true; trusted_change = true;
if (content.Trusted.remove) if (content.Trusted.remove)
for (let id of content.Trusted.remove) for (let id of content.Trusted.remove)
promises.push(DB.query("DELETE FROM trustedList WHERE floID=?", [id])); promises.push(DB.query("DELETE FROM TrustedList WHERE floID=?", [id]));
if (content.Trusted.add) if (content.Trusted.add)
for (let id of content.Trusted.add) for (let id of content.Trusted.add)
promises.push(DB.query("INSERT INTO trustedList (floID) VALUE (?) AS new ON DUPLICATE KEY UPDATE floID=new.floID", [id])); promises.push(DB.query("INSERT INTO TrustedList (floID) VALUE (?) AS new ON DUPLICATE KEY UPDATE floID=new.floID", [id]));
} }
//Tag List with priority and API //Tag List with priority and API
if (content.Tag) { if (content.Tag) {
@ -71,7 +78,7 @@ function refreshDataFromBlockchain() {
promises.push(`UPDATE TagList WHERE tag=? SET ${a}=?`, [t, content.Tag.update[t][a]]); promises.push(`UPDATE TagList WHERE tag=? SET ${a}=?`, [t, content.Tag.update[t][a]]);
} }
}); });
promises.push(DB.query("INSERT INTO lastTx (floID, num) VALUE (?, ?) AS new ON DUPLICATE KEY UPDATE num=new.num", [floGlobals.adminID, result.totalTxs])); promises.push(DB.query("INSERT INTO LastTx (floID, num) VALUE (?, ?) AS new ON DUPLICATE KEY UPDATE num=new.num", [floGlobals.adminID, result.totalTxs]));
//Check if all save process were successful //Check if all save process were successful
Promise.allSettled(promises).then(results => { Promise.allSettled(promises).then(results => {
console.debug(results.filter(r => r.status === "rejected")); console.debug(results.filter(r => r.status === "rejected"));
@ -80,6 +87,7 @@ function refreshDataFromBlockchain() {
}); });
resolve({ resolve({
nodes: nodes_change, nodes: nodes_change,
assets: assets_change,
trusted: trusted_change trusted: trusted_change
}); });
}).catch(error => reject(error)); }).catch(error => reject(error));
@ -92,6 +100,8 @@ function loadDataFromDB(changes, startup) {
let promises = []; let promises = [];
if (startup || changes.nodes) if (startup || changes.nodes)
promises.push(loadDataFromDB.nodeList()); promises.push(loadDataFromDB.nodeList());
if (startup || changes.assets)
promises.push(loadDataFromDB.assetList());
if (startup || changes.trusted) if (startup || changes.trusted)
promises.push(loadDataFromDB.trustedIDs()); promises.push(loadDataFromDB.trustedIDs());
Promise.all(promises) Promise.all(promises)
@ -102,7 +112,7 @@ function loadDataFromDB(changes, startup) {
loadDataFromDB.nodeList = function() { loadDataFromDB.nodeList = function() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT * FROM nodeList").then(result => { DB.query("SELECT floID, uri FROM NodeList").then(result => {
let nodes = {} let nodes = {}
for (let i in result) for (let i in result)
nodes[result[i].floID] = result[i].uri; nodes[result[i].floID] = result[i].uri;
@ -113,9 +123,23 @@ loadDataFromDB.nodeList = function() {
}) })
} }
loadDataFromDB.assetList = function() {
return new Promise((resolve, reject) => {
DB.query("SELECT asset FROM AssetList").then(result => {
let assets = [];
for (let i in result)
assets.push(result[i].asset);
//update dependents
backup.assetList = assets;
app.assetList = assets;
resolve(assets);
}).catch(error => reject(error))
})
}
loadDataFromDB.trustedIDs = function() { loadDataFromDB.trustedIDs = function() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT * FROM trustedList").then(result => { DB.query("SELECT * FROM TrustedList").then(result => {
let trustedIDs = []; let trustedIDs = [];
for (let i in result) for (let i in result)
trustedIDs.push(result[i].floID); trustedIDs.push(result[i].floID);

View File

@ -3,9 +3,59 @@
const coupling = require('./coupling'); const coupling = require('./coupling');
const MINIMUM_BUY_REQUIREMENT = 0.1; const MINIMUM_BUY_REQUIREMENT = 0.1;
var DB; //container for database var DB, assetList; //container for database and allowed assets
function addSellOrder(floID, quantity, min_price) { const getAssetBalance = (floID, asset) => new Promise((resolve, reject) => {
let promises = (asset === floGlobals.currency) ? [
DB.query("SELECT balance FROM Cash WHERE floID=?", [floID]),
DB.query("SELECT SUM(quantity*maxPrice) AS locked FROM BuyOrder WHERE floID=?", [floID])
] : [
DB.query("SELECT SUM(quantity) AS balance FROM Vault WHERE floID=? AND asset=?", [floID, asset]),
DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=? AND asset=?", [floID, asset])
];
Promise.all(promises).then(result => resolve({
total: result[0][0].balance,
locked: result[1][0].locked,
net: result[0][0].balance - result[1][0].locked
})).catch(error => reject(error))
});
getAssetBalance.check = (floID, asset, amount) => new Promise((resolve, reject) => {
getAssetBalance(floID, asset).then(balance => {
if (balance.total < amount)
reject(INVALID(`Insufficient ${asset}`));
else if (balance.net < amount)
reject(INVALID(`Insufficient ${asset} (Some are locked in orders)`));
else
resolve(true);
}).catch(error => reject(error))
})
const consumeAsset = (floID, asset, amount, txQueries = []) => new Promise((resolve, reject) => {
//If asset/token is currency update Cash else consume from Vault
if (asset === floGlobals.currency) {
txQueries.push(["UPDATE Cash SET balance=balance-? WHERE floID=?", [amount, floID]]);
return resolve(txQueries);
} else
DB.query("SELECT id, quantity FROM Vault WHERE floID=? AND asset=? ORDER BY locktime", [floID, asset]).then(coins => {
let rem = amount;
for (let i = 0; i < coins.length && rem > 0; i++) {
if (rem < coins[i].quantity) {
txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, coins[i].id]]);
rem = 0;
} else {
txQueries.push(["DELETE FROM Vault WHERE id=?", [coins[i].id]]);
rem -= result[i].quantity;
}
}
if (rem > 0) //should not happen AS the total and net is checked already
reject(INVALID("Insufficient Asset"));
else
resolve(txQueries);
}).catch(error => reject(error));
});
function addSellOrder(floID, asset, quantity, min_price) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!floID || !floCrypto.validateAddr(floID)) if (!floID || !floCrypto.validateAddr(floID))
return reject(INVALID("Invalid FLO ID")); return reject(INVALID("Invalid FLO ID"));
@ -13,41 +63,33 @@ function addSellOrder(floID, quantity, min_price) {
return reject(INVALID(`Invalid quantity (${quantity})`)); return reject(INVALID(`Invalid quantity (${quantity})`));
else if (typeof min_price !== "number" || min_price <= 0) else if (typeof min_price !== "number" || min_price <= 0)
return reject(INVALID(`Invalid min_price (${min_price})`)); return reject(INVALID(`Invalid min_price (${min_price})`));
checkSellRequirement(floID).then(_ => { else if (!assetList.includes(asset))
DB.query("SELECT SUM(quantity) AS total FROM Vault WHERE floID=?", [floID]).then(result => { return reject(INVALID(`Invalid asset (${asset})`));
let total = result.pop()["total"] || 0; getAssetBalance.check(floID, asset, quantity).then(_ => {
if (total < quantity) checkSellRequirement(floID).then(_ => {
return reject(INVALID("Insufficient FLO")); DB.query("INSERT INTO SellOrder(floID, asset, quantity, minPrice) VALUES (?, ?, ?, ?)", [floID, asset, quantity, min_price])
DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=?", [floID]).then(result => { .then(result => resolve("Added SellOrder to DB"))
let locked = result.pop()["locked"] || 0; .catch(error => reject(error));
let available = total - locked; }).catch(error => reject(error))
if (available < quantity)
return reject(INVALID("Insufficient FLO (Some FLO are locked in another sell order)"));
DB.query("INSERT INTO SellOrder(floID, quantity, minPrice) VALUES (?, ?, ?)", [floID, quantity, min_price])
.then(result => resolve("Added SellOrder to DB"))
.catch(error => reject(error));
}).catch(error => reject(error));
}).catch(error => reject(error));
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
} }
function checkSellRequirement(floID) { const checkSellRequirement = floID => new Promise((resolve, reject) => {
return new Promise((resolve, reject) => { DB.query("SELECT * FROM UserTag WHERE floID=? AND tag=?", [floID, "MINER"]).then(result => {
DB.query("SELECT * FROM Tags WHERE floID=? AND tag=?", [floID, "MINER"]).then(result => { if (result.length)
if (result.length) return resolve(true);
return resolve(true); //TODO: Should seller need to buy same type of asset before selling?
DB.query("SELECT SUM(quantity) AS brought FROM Transactions WHERE buyer=?", [floID]).then(result => { DB.query("SELECT SUM(quantity) AS brought FROM TransactionHistory WHERE buyer=?", [floID]).then(result => {
if (result[0].brought >= MINIMUM_BUY_REQUIREMENT) if (result[0].brought >= MINIMUM_BUY_REQUIREMENT)
resolve(true); resolve(true);
else else
reject(INVALID(`Sellers required to buy atleast ${MINIMUM_BUY_REQUIREMENT} FLO before placing a sell order unless they are a Miner`)); reject(INVALID(`Sellers required to buy atleast ${MINIMUM_BUY_REQUIREMENT} FLO before placing a sell order unless they are a Miner`));
}).catch(error => reject(error))
}).catch(error => reject(error)) }).catch(error => reject(error))
}) }).catch(error => reject(error))
} });
function addBuyOrder(floID, quantity, max_price) { function addBuyOrder(floID, asset, quantity, max_price) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!floID || !floCrypto.validateAddr(floID)) if (!floID || !floCrypto.validateAddr(floID))
return reject(INVALID("Invalid FLO ID")); return reject(INVALID("Invalid FLO ID"));
@ -55,21 +97,12 @@ function addBuyOrder(floID, quantity, max_price) {
return reject(INVALID(`Invalid quantity (${quantity})`)); return reject(INVALID(`Invalid quantity (${quantity})`));
else if (typeof max_price !== "number" || max_price <= 0) else if (typeof max_price !== "number" || max_price <= 0)
return reject(INVALID(`Invalid max_price (${max_price})`)); return reject(INVALID(`Invalid max_price (${max_price})`));
DB.query("SELECT rupeeBalance FROM Cash WHERE floID=?", [floID]).then(result => { else if (!assetList.includes(asset))
if (result.length < 1) return reject(INVALID(`Invalid asset (${asset})`));
return reject(INVALID("FLO ID not registered")); getAssetBalance.check(floID, asset, quantity).then(_ => {
let total = result.pop()["rupeeBalance"]; DB.query("INSERT INTO BuyOrder(floID, asset, quantity, maxPrice) VALUES (?, ?, ?, ?)", [floID, asset, quantity, max_price])
if (total < quantity * max_price) .then(result => resolve("Added BuyOrder to DB"))
return reject(INVALID("Insufficient Rupee balance")); .catch(error => reject(error));
DB.query("SELECT SUM(maxPrice * quantity) AS locked FROM BuyOrder WHERE floID=?", [floID]).then(result => {
let locked = result.pop()["locked"] || 0;
let available = total - locked;
if (available < quantity * max_price)
return reject(INVALID("Insufficient Rupee balance (Some rupee tokens are locked in another buy order)"));
DB.query("INSERT INTO BuyOrder(floID, quantity, maxPrice) VALUES (?, ?, ?)", [floID, quantity, max_price])
.then(result => resolve("Added BuyOrder to DB"))
.catch(error => reject(error));
}).catch(error => reject(error));
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
} }
@ -101,11 +134,11 @@ function cancelOrder(type, id, floID) {
function getAccountDetails(floID) { function getAccountDetails(floID) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let select = []; let select = [];
select.push(["rupeeBalance", "Cash"]); select.push(["balance", "Cash"]);
select.push(["base, quantity", "Vault"]); select.push(["asset, AVG(base) AS avg_base, SUM(quantity) AS quantity", "Vault", "GROUP BY asset"]);
select.push(["id, quantity, minPrice, time_placed", "SellOrder"]); select.push(["id, asset, quantity, minPrice, time_placed", "SellOrder"]);
select.push(["id, quantity, maxPrice, time_placed", "BuyOrder"]); select.push(["id, asset, quantity, maxPrice, time_placed", "BuyOrder"]);
let promises = select.map(a => DB.query("SELECT " + a[0] + " FROM " + a[1] + " WHERE floID=?", [floID])); let promises = select.map(a => DB.query(`SELECT ${a[0]} FROM ${a[1]} WHERE floID=? ${a[2] || ""}`, [floID]));
Promise.allSettled(promises).then(results => { Promise.allSettled(promises).then(results => {
let response = { let response = {
floID: floID, floID: floID,
@ -117,10 +150,10 @@ function getAccountDetails(floID) {
else else
switch (i) { switch (i) {
case 0: case 0:
response.rupee_total = a.value[0].rupeeBalance; response.cash = a.value[0].balance;
break; break;
case 1: case 1:
response.coins = a.value; response.vault = a.value;
break; break;
case 2: case 2:
response.sellOrders = a.value; response.sellOrders = a.value;
@ -130,7 +163,7 @@ function getAccountDetails(floID) {
break; break;
} }
}); });
DB.query("SELECT * FROM Transactions WHERE seller=? OR buyer=?", [floID, floID]) DB.query("SELECT * FROM TransactionHistory WHERE seller=? OR buyer=?", [floID, floID])
.then(result => response.transactions = result) .then(result => response.transactions = result)
.catch(error => console.error(error)) .catch(error => console.error(error))
.finally(_ => resolve(response)); .finally(_ => resolve(response));
@ -140,7 +173,7 @@ function getAccountDetails(floID) {
function depositFLO(floID, txid) { function depositFLO(floID, txid) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT status FROM inputFLO WHERE txid=? AND floID=?", [txid, floID]).then(result => { DB.query("SELECT status FROM InputFLO WHERE txid=? AND floID=?", [txid, floID]).then(result => {
if (result.length) { if (result.length) {
switch (result[0].status) { switch (result[0].status) {
case "PENDING": case "PENDING":
@ -151,7 +184,7 @@ function depositFLO(floID, txid) {
return reject(INVALID("Transaction already used to add coins")); return reject(INVALID("Transaction already used to add coins"));
} }
} else } else
DB.query("INSERT INTO inputFLO(txid, floID, status) VALUES (?, ?, ?)", [txid, floID, "PENDING"]) DB.query("INSERT INTO InputFLO(txid, floID, status) VALUES (?, ?, ?)", [txid, floID, "PENDING"])
.then(result => resolve("Deposit request in process")) .then(result => resolve("Deposit request in process"))
.catch(error => reject(error)); .catch(error => reject(error));
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -159,19 +192,19 @@ function depositFLO(floID, txid) {
} }
function confirmDepositFLO() { function confirmDepositFLO() {
DB.query("SELECT id, floID, txid FROM inputFLO WHERE status=?", ["PENDING"]).then(results => { DB.query("SELECT id, floID, txid FROM InputFLO WHERE status=?", ["PENDING"]).then(results => {
results.forEach(req => { results.forEach(req => {
confirmDepositFLO.checkTx(req.floID, req.txid).then(amount => { confirmDepositFLO.checkTx(req.floID, req.txid).then(amount => {
let txQueries = []; let txQueries = [];
txQueries.push(["INSERT INTO Vault(floID, quantity) VALUES (?, ?)", [req.floID, amount]]); txQueries.push(["INSERT INTO Vault(floID, quantity) VALUES (?, ?)", [req.floID, 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 for ", req.floID)) .then(result => console.debug("FLO deposited:", req.floID, amount))
.catch(error => console.error(error)) .catch(error => console.error(error))
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
if (error[0]) if (error[0])
DB.query("UPDATE inputFLO SET status=? WHERE id=?", ["REJECTED", req.id]) DB.query("UPDATE InputFLO SET status=? WHERE id=?", ["REJECTED", req.id])
.then(_ => null).catch(error => console.error(error)); .then(_ => null).catch(error => console.error(error));
}); });
}) })
@ -206,45 +239,23 @@ function withdrawFLO(floID, amount) {
return reject(INVALID("Invalid FLO ID")); return reject(INVALID("Invalid FLO ID"));
else if (typeof amount !== "number" || amount <= 0) else if (typeof amount !== "number" || amount <= 0)
return reject(INVALID(`Invalid amount (${amount})`)); return reject(INVALID(`Invalid amount (${amount})`));
DB.query("SELECT SUM(quantity) AS total FROM Vault WHERE floID=?", [floID]).then(result => { getAssetBalance.check(floID, "FLO", amount).then(_ => {
let total = result.pop()["total"] || 0; consumeAsset(floID, "FLO", amount).then(txQueries => {
if (total < amount) DB.transaction(txQueries).then(result => {
return reject(INVALID("Insufficient FLO")); //Send FLO to user via blockchain API
DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=?", [floID]).then(result => { floBlockchainAPI.sendTx(global.myFloID, floID, amount, global.myPrivKey, 'Withdraw FLO Coins from Market').then(txid => {
let locked = result.pop()["locked"] || 0; if (!txid)
let available = total - locked; throw Error("Transaction not successful");
if (available < amount) //Transaction was successful, Add in DB
return reject(INVALID("Insufficient FLO (Some FLO are locked in sell orders)")); DB.query("INSERT INTO OutputFLO (floID, amount, txid, status) VALUES (?, ?, ?, ?)", [floID, amount, txid, "WAITING_CONFIRMATION"])
DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY locktime", [floID]).then(coins => { .then(_ => null).catch(error => console.error(error))
let rem = amount, .finally(_ => resolve("Withdrawal was successful"));
txQueries = []; }).catch(error => {
for (let i = 0; i < coins.length && rem > 0; i++) { console.debug(error);
if (rem < coins[i].quantity) { DB.query("INSERT INTO OutputFLO (floID, amount, status) VALUES (?, ?, ?)", [floID, amount, "PENDING"])
txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, coins[i].id]]); .then(_ => null).catch(error => console.error(error))
rem = 0; .finally(_ => resolve("Withdrawal request is in process"));
} else { });
txQueries.push(["DELETE FROM Vault WHERE id=?", [coins[i].id]]);
rem -= coins[i].quantity;
}
}
if (rem > 0) //should not happen AS the total and net is checked already
return reject(INVALID("Insufficient FLO"));
DB.transaction(txQueries).then(result => {
//Send FLO to user via blockchain API
floBlockchainAPI.sendTx(global.myFloID, floID, amount, global.myPrivKey, 'Withdraw FLO Coins from Market').then(txid => {
if (!txid)
throw Error("Transaction not successful");
//Transaction was successful, Add in DB
DB.query("INSERT INTO outputFLO (floID, amount, txid, status) VALUES (?, ?, ?, ?)", [floID, amount, txid, "WAITING_CONFIRMATION"])
.then(_ => null).catch(error => console.error(error))
.finally(_ => resolve("Withdrawal was successful"));
}).catch(error => {
console.debug(error);
DB.query("INSERT INTO outputFLO (floID, amount, status) VALUES (?, ?, ?)", [floID, amount, "PENDING"])
.then(_ => null).catch(error => console.error(error))
.finally(_ => resolve("Withdrawal request is in process"));
});
}).catch(error => reject(error));
}).catch(error => reject(error)); }).catch(error => reject(error));
}).catch(error => reject(error)); }).catch(error => reject(error));
}).catch(error => reject(error)); }).catch(error => reject(error));
@ -252,13 +263,13 @@ function withdrawFLO(floID, amount) {
} }
function retryWithdrawalFLO() { function retryWithdrawalFLO() {
DB.query("SELECT id, floID, amount FROM outputFLO WHERE status=?", ["PENDING"]).then(results => { DB.query("SELECT id, floID, amount FROM OutputFLO WHERE status=?", ["PENDING"]).then(results => {
results.forEach(req => { results.forEach(req => {
floBlockchainAPI.sendTx(global.myFloID, req.floID, req.amount, global.myPrivKey, 'Withdraw FLO Coins from Market').then(txid => { floBlockchainAPI.sendTx(global.myFloID, req.floID, req.amount, global.myPrivKey, 'Withdraw FLO Coins from Market').then(txid => {
if (!txid) if (!txid)
throw Error("Transaction not successful"); throw Error("Transaction not successful");
//Transaction was successful, Add in DB //Transaction was successful, Add in DB
DB.query("UPDATE outputFLO SET status=? WHERE id=?", ["WAITING_CONFIRMATION", req.id]) DB.query("UPDATE OutputFLO SET status=? WHERE id=?", ["WAITING_CONFIRMATION", req.id])
.then(_ => null).catch(error => console.error(error)); .then(_ => null).catch(error => console.error(error));
}).catch(error => console.error(error)); }).catch(error => console.error(error));
}) })
@ -266,22 +277,22 @@ function retryWithdrawalFLO() {
} }
function confirmWithdrawalFLO() { function confirmWithdrawalFLO() {
DB.query("SELECT id, floID, txid FROM outputFLO WHERE status=?", ["WAITING_CONFIRMATION"]).then(results => { DB.query("SELECT id, floID, amount, txid FROM OutputFLO WHERE status=?", ["WAITING_CONFIRMATION"]).then(results => {
results.forEach(req => { results.forEach(req => {
floBlockchainAPI.getTx(req.txid).then(tx => { floBlockchainAPI.getTx(req.txid).then(tx => {
if (!tx.blockheight || !tx.confirmations) //Still not confirmed if (!tx.blockheight || !tx.confirmations) //Still not confirmed
return; return;
DB.query("UPDATE outputFLO SET status=? WHERE id=?", ["SUCCESS", req.id]) DB.query("UPDATE OutputFLO SET status=? WHERE id=?", ["SUCCESS", req.id])
.then(result => console.debug("FLO withdrawed for ", req.floID)) .then(result => console.debug("FLO withdrawed:", req.floID, req.amount))
.catch(error => console.error(error)) .catch(error => console.error(error))
}).catch(error => console.error(error)); }).catch(error => console.error(error));
}) })
}).catch(error => console.error(error)); }).catch(error => console.error(error));
} }
function depositRupee(floID, txid) { function depositToken(floID, txid) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT status FROM inputRupee WHERE txid=? AND floID=?", [txid, floID]).then(result => { DB.query("SELECT status FROM InputToken WHERE txid=? AND floID=?", [txid, floID]).then(result => {
if (result.length) { if (result.length) {
switch (result[0].status) { switch (result[0].status) {
case "PENDING": case "PENDING":
@ -292,53 +303,58 @@ function depositRupee(floID, txid) {
return reject(INVALID("Transaction already used to add tokens")); return reject(INVALID("Transaction already used to add tokens"));
} }
} else } else
DB.query("INSERT INTO inputRupee(txid, floID, status) VALUES (?, ?, ?)", [txid, floID, "PENDING"]) DB.query("INSERT INTO InputToken(txid, floID, status) VALUES (?, ?, ?)", [txid, floID, "PENDING"])
.then(result => resolve("Deposit request in process")) .then(result => resolve("Deposit request in process"))
.catch(error => reject(error)); .catch(error => reject(error));
}).catch(error => reject(error)) }).catch(error => reject(error))
}); });
} }
function confirmDepositRupee() { function confirmDepositToken() {
DB.query("SELECT id, floID, txid FROM inputRupee WHERE status=?", ["PENDING"]).then(results => { DB.query("SELECT id, floID, txid FROM InputToken WHERE status=?", ["PENDING"]).then(results => {
results.forEach(req => { results.forEach(req => {
confirmDepositRupee.checkTx(req.floID, req.txid).then(amounts => { confirmDepositToken.checkTx(req.floID, req.txid).then(amounts => {
DB.query("SELECT id FROM inputFLO where floID=? AND txid=?", [req.floID, req.txid]).then(result => { DB.query("SELECT id FROM InputFLO where floID=? AND txid=?", [req.floID, req.txid]).then(result => {
let txQueries = [], let txQueries = [],
amount_rupee = amounts[0]; token_name = amounts[0],
amount_token = amounts[1];
//Add the FLO balance if necessary //Add the FLO balance if necessary
if (!result.length) { if (!result.length) {
let amount_flo = amounts[1]; let amount_flo = amounts[2];
txQueries.push(["INSERT INTO Vault(floID, quantity) VALUES (?, ?)", [req.floID, amount_flo]]); txQueries.push(["INSERT INTO Vault(floID, asset, quantity) VALUES (?, ?, ?)", [req.floID, "FLO", amount_flo]]);
txQueries.push(["INSERT INTO inputFLO(txid, floID, amount, status) VALUES (?, ?, ?, ?)", [req.txid, req.floID, amount_flo, "SUCCESS"]]); txQueries.push(["INSERT INTO InputFLO(txid, floID, amount, status) VALUES (?, ?, ?, ?)", [req.txid, req.floID, amount_flo, "SUCCESS"]]);
} }
txQueries.push(["UPDATE inputRupee SET status=? WHERE id=?", ["SUCCESS", req.id]]); txQueries.push(["UPDATE InputToken SET status=?, token=?, amount=? WHERE id=?", ["SUCCESS", token_name, amount_token, req.id]]);
txQueries.push(["UPDATE Cash SET rupeeBalance=rupeeBalance+? WHERE floID=?", [amount_rupee, req.floID]]); if (token_name === floGlobals.currency)
txQueries.push(["UPDATE Cash SET balance=balance+? WHERE floID=?", [amount_token, req.floID]]);
else
txQueries.push(["INSERT INTO Vault(floID, asset, quantity) VALUES (?, ?, ?)", [req.floID, token_name, amount_token]]);
DB.transaction(txQueries) DB.transaction(txQueries)
.then(result => console.debug("Rupee deposited for ", req.floID)) .then(result => console.debug("Token deposited:", req.floID, token_name, amount_token))
.catch(error => console.error(error)); .catch(error => console.error(error));
}).catch(error => console.error(error)); }).catch(error => console.error(error));
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
if (error[0]) if (error[0])
DB.query("UPDATE inputRupee SET status=? WHERE id=?", ["REJECTED", req.id]) DB.query("UPDATE InputToken SET status=? WHERE id=?", ["REJECTED", req.id])
.then(_ => null).catch(error => console.error(error)); .then(_ => null).catch(error => console.error(error));
}); });
}) })
}).catch(error => console.error(error)) }).catch(error => console.error(error))
} }
confirmDepositRupee.checkTx = function(sender, txid) { confirmDepositToken.checkTx = function(sender, txid) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const receiver = global.myFloID; //receiver should be market's floID (ie, adminID) const receiver = global.sinkID; //receiver should be market's floID (ie, sinkID)
tokenAPI.getTx(txid).then(tx => { tokenAPI.getTx(txid).then(tx => {
if (tx.parsedFloData.type !== "transfer") if (tx.parsedFloData.type !== "transfer")
return reject([true, "Transaction type not 'transfer'"]); return reject([true, "Transaction type not 'transfer'"]);
else if (tx.parsedFloData.transferType !== "token") else if (tx.parsedFloData.transferType !== "token")
return reject([true, "Transaction transfer is not 'token'"]); return reject([true, "Transaction transfer is not 'token'"]);
else if (tx.parsedFloData.tokenIdentification !== "rupee") var token_name = tx.parsedFloData.tokenIdentification,
return reject([true, "Transaction token is not 'rupee'"]); amount_token = tx.parsedFloData.tokenAmount;
var amount_rupee = tx.parsedFloData.tokenAmount; if (!assetList.includes(token_name) || token_name === "FLO")
return reject([true, "Token not authorised"]);
let vin_sender = tx.transactionDetails.vin.filter(v => v.addr === sender) let vin_sender = tx.transactionDetails.vin.filter(v => v.addr === sender)
if (!vin_sender.length) if (!vin_sender.length)
return reject([true, "Transaction not sent by the sender"]); return reject([true, "Transaction not sent by the sender"]);
@ -346,60 +362,36 @@ confirmDepositRupee.checkTx = function(sender, txid) {
if (amount_flo == 0) if (amount_flo == 0)
return reject([true, "Transaction receiver is not market ID"]); return reject([true, "Transaction receiver is not market ID"]);
else else
resolve([amount_rupee, amount_flo]); resolve([token_name, amount_token, amount_flo]);
}).catch(error => reject([false, error])) }).catch(error => reject([false, error]))
}) })
} }
function withdrawRupee(floID, amount) { function withdrawToken(floID, token, amount) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!floID || !floCrypto.validateAddr(floID)) if (!floID || !floCrypto.validateAddr(floID))
return reject(INVALID("Invalid FLO ID")); return reject(INVALID("Invalid FLO ID"));
else if (typeof amount !== "number" || amount <= 0) else if (typeof amount !== "number" || amount <= 0)
return reject(INVALID(`Invalid amount (${amount})`)); return reject(INVALID(`Invalid amount (${amount})`));
DB.query("SELECT SUM(quantity) AS total FROM Vault WHERE floID=?", [floID]).then(result => { else if (!assetList.includes(token) || token === "FLO")
let required_flo = floGlobals.sendAmt + floGlobals.fee, return reject(INVALID("Invalid Token"));
total = result.pop()["total"] || 0; //Check for FLO balance (transaction fee)
if (total < required_flo) const required_flo = floGlobals.sendAmt + floGlobals.fee;
return reject(INVALID(`Insufficient FLO! Required ${required_flo} FLO to withdraw tokens`)); getAssetBalance.check(floID, "FLO", required_flo).then(_ => {
DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=?", [floID]).then(result => { getAssetBalance.check(floID, token, amount).then(_ => {
let locked = result.pop()["locked"] || 0; consumeAsset(floID, "FLO", required_flo).then(txQueries => {
let available = total - locked; consumeAsset(floID, token, amount, txQueries).then(txQueries => {
if (available < required_flo)
return reject(INVALID(`Insufficient FLO (Some FLO are locked in sell orders)! Required ${required_flo} FLO to withdraw tokens`));
DB.query("SELECT rupeeBalance FROM Cash WHERE floID=?", [floID]).then(result => {
if (result.length < 1)
return reject(INVALID(`FLO_ID: ${floID} not registered`));
if (result[0].rupeeBalance < amount)
return reject(INVALID('Insufficient Rupee balance'));
DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY locktime", [floID]).then(coins => {
let rem = required_flo,
txQueries = [];
for (let i = 0; i < coins.length && rem > 0; i++) {
if (rem < coins[i].quantity) {
txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, coins[i].id]]);
rem = 0;
} else {
txQueries.push(["DELETE FROM Vault WHERE id=?", [coins[i].id]]);
rem -= result[i].quantity;
}
}
if (rem > 0) //should not happen AS the total and net is checked already
return reject(INVALID("Insufficient FLO"));
txQueries.push(["UPDATE Cash SET rupeeBalance=rupeeBalance-? WHERE floID=?", [amount, floID]]);
DB.transaction(txQueries).then(result => { DB.transaction(txQueries).then(result => {
//Send FLO to user via blockchain API //Send FLO to user via blockchain API
tokenAPI.sendToken(global.myPrivKey, amount, '(withdrawal from market)', floID).then(txid => { tokenAPI.sendToken(global.myPrivKey, amount, floID, '(withdrawal from market)', token).then(txid => {
if (!txid) if (!txid) throw Error("Transaction not successful");
throw Error("Transaction not successful");
//Transaction was successful, Add in DB //Transaction was successful, Add in DB
DB.query("INSERT INTO outputRupee (floID, amount, txid, status) VALUES (?, ?, ?, ?)", [floID, amount, txid, "WAITING_CONFIRMATION"]) DB.query("INSERT INTO OutputToken (floID, token, amount, txid, status) VALUES (?, ?, ?, ?, ?)", [floID, token, amount, txid, "WAITING_CONFIRMATION"])
.then(_ => null).catch(error => console.error(error)) .then(_ => null).catch(error => console.error(error))
.finally(_ => resolve("Withdrawal was successful")); .finally(_ => resolve("Withdrawal was successful"));
}).catch(error => { }).catch(error => {
console.debug(error); console.debug(error);
DB.query("INSERT INTO outputRupee (floID, amount, status) VALUES (?, ?, ?)", [floID, amount, "PENDING"]) DB.query("INSERT INTO OutputToken (floID, token, amount, status) VALUES (?, ?, ?, ?)", [floID, token, amount, "PENDING"])
.then(_ => null).catch(error => console.error(error)) .then(_ => null).catch(error => console.error(error))
.finally(_ => resolve("Withdrawal request is in process")); .finally(_ => resolve("Withdrawal request is in process"));
}); });
@ -411,26 +403,26 @@ function withdrawRupee(floID, amount) {
}); });
} }
function retryWithdrawalRupee() { function retryWithdrawalToken() {
DB.query("SELECT id, floID, amount FROM outputRupee WHERE status=?", ["PENDING"]).then(results => { DB.query("SELECT id, floID, token, amount FROM OutputToken WHERE status=?", ["PENDING"]).then(results => {
results.forEach(req => { results.forEach(req => {
tokenAPI.sendToken(global.myPrivKey, req.amount, '(withdrawal from market)', req.floID).then(txid => { tokenAPI.sendToken(global.myPrivKey, req.amount, req.floID, '(withdrawal from market)', req.token).then(txid => {
if (!txid) if (!txid)
throw Error("Transaction not successful"); throw Error("Transaction not successful");
//Transaction was successful, Add in DB //Transaction was successful, Add in DB
DB.query("UPDATE outputRupee SET status=?, txid=? WHERE id=?", ["WAITING_CONFIRMATION", txid, req.id]) DB.query("UPDATE OutputToken SET status=?, txid=? WHERE id=?", ["WAITING_CONFIRMATION", txid, req.id])
.then(_ => null).catch(error => console.error(error)); .then(_ => null).catch(error => console.error(error));
}).catch(error => console.error(error)); }).catch(error => console.error(error));
}); });
}).catch(error => reject(error)); }).catch(error => reject(error));
} }
function confirmWithdrawalRupee() { function confirmWithdrawalToken() {
DB.query("SELECT id, floID, amount, txid FROM outputRupee WHERE status=?", ["WAITING_CONFIRMATION"]).then(results => { DB.query("SELECT id, floID, token, amount, txid FROM OutputToken WHERE status=?", ["WAITING_CONFIRMATION"]).then(results => {
results.forEach(req => { results.forEach(req => {
tokenAPI.getTx(req.txid).then(tx => { tokenAPI.getTx(req.txid).then(tx => {
DB.query("UPDATE outputRupee SET status=? WHERE id=?", ["SUCCESS", req.id]) DB.query("UPDATE OutputToken SET status=? WHERE id=?", ["SUCCESS", req.id])
.then(result => console.debug("Rupee withdrawed for ", req.floID)) .then(result => console.debug("Token withdrawed:", req.floID, req.token, req.amount))
.catch(error => console.error(error)); .catch(error => console.error(error));
}).catch(error => console.error(error)); }).catch(error => console.error(error));
}) })
@ -439,21 +431,21 @@ function confirmWithdrawalRupee() {
function periodicProcess() { function periodicProcess() {
blockchainReCheck(); blockchainReCheck();
coupling.initiate(); assetList.forEach(asset => coupling.initiate(asset));
} }
function blockchainReCheck() { function blockchainReCheck() {
confirmDepositFLO(); confirmDepositFLO();
confirmDepositRupee(); confirmDepositToken();
retryWithdrawalFLO(); retryWithdrawalFLO();
retryWithdrawalRupee(); retryWithdrawalToken();
confirmWithdrawalFLO(); confirmWithdrawalFLO();
confirmWithdrawalRupee(); confirmWithdrawalToken();
} }
module.exports = { module.exports = {
get rate() { get rates() {
return coupling.price.currentRate; return coupling.price.currentRates;
}, },
addBuyOrder, addBuyOrder,
addSellOrder, addSellOrder,
@ -461,12 +453,15 @@ module.exports = {
getAccountDetails, getAccountDetails,
depositFLO, depositFLO,
withdrawFLO, withdrawFLO,
depositRupee, depositToken,
withdrawRupee, withdrawToken,
periodicProcess, periodicProcess,
group: coupling.group, group: coupling.group,
set DB(db) { set DB(db) {
DB = db; DB = db;
coupling.DB = db; coupling.DB = db;
},
set assetList(assets) {
assetList = assets;
} }
}; };

View File

@ -10,41 +10,48 @@ const MIN_TIME = 10 * 1000, // 1 * 60 * 60 * 1000,
var DB; //container for database var DB; //container for database
var cur_rate, //container for FLO price (from API or by model) var currentRate = {}, //container for FLO price (from API or by model)
lastTime = Date.now(), //container for timestamp of the last tx lastTime = {}, //container for timestamp of the last tx
noBuyOrder, noBuyOrder = {},
noSellOrder; noSellOrder = {};
const updateLastTime = () => lastTime = Date.now(); const updateLastTime = asset => lastTime[asset] = Date.now();
//store FLO price in DB every 1 hr //store FLO price in DB every 1 hr
function storeRate(rate = cur_rate) { function storeRate(asset, rate) {
DB.query("INSERT INTO priceHistory (rate) VALUE (?)", rate) DB.query("INSERT INTO PriceHistory (asset, rate) VALUE (?, ?)", [asset, rate])
.then(_ => null).catch(error => console.error(error)) .then(_ => null).catch(error => console.error(error))
} }
setInterval(storeRate, REC_HISTORY_INTERVAL) setInterval(() => {
for (let asset in currentRate)
storeRate(asset, currentRate[asset]);
}, REC_HISTORY_INTERVAL)
function getPastRate(hrs = 24) { function getPastRate(asset, hrs = 24) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT rate FROM priceHistory WHERE rec_time >= NOW() - INTERVAL ? hour ORDER BY rec_time LIMIT 1", [hrs]) DB.query("SELECT rate FROM PriceHistory WHERE asset=? AND rec_time >= NOW() - INTERVAL ? hour ORDER BY rec_time LIMIT 1", [asset, hrs])
.then(result => result.length ? resolve(result[0].rate) : reject('No records found in past 24hrs')) .then(result => result.length ? resolve(result[0].rate) : reject('No records found in past 24hrs'))
.catch(error => reject(error)) .catch(error => reject(error))
}); });
} }
function loadRate() { function loadRate(asset) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (typeof cur_rate !== "undefined") if (typeof currentRate[asset] !== "undefined")
return resolve(cur_rate); return resolve(currentRate[asset]);
DB.query("SELECT rate FROM priceHistory ORDER BY rec_time DESC LIMIT 1").then(result => { updateLastTime(asset);
DB.query("SELECT rate FROM PriceHistory WHERE asset=? ORDER BY rec_time DESC LIMIT 1", [asset]).then(result => {
if (result.length) if (result.length)
resolve(cur_rate = result[0].rate); resolve(currentRate[asset] = result[0].rate);
else else
fetchRates().then(rate => resolve(cur_rate = rate)).catch(error => reject(error)); DB.query("SELECT initialPrice FROM AssetList WHERE asset=?", [asset])
.then(result => resolve(currentRate[asset] = result[0].initialPrice))
.catch(error => reject(error))
}).catch(error => reject(error)); }).catch(error => reject(error));
}) })
} }
/*
function fetchRates() { function fetchRates() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fetchRates.FLO_USD().then(FLO_rate => { fetchRates.FLO_USD().then(FLO_rate => {
@ -83,57 +90,58 @@ fetchRates.USD_INR = function() {
}).catch(error => reject(error)); }).catch(error => reject(error));
}); });
} }
*/
function getRates() { function getRates(asset) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
loadRate().then(_ => { loadRate(asset).then(_ => {
console.debug(cur_rate); console.debug(asset, currentRate[asset]);
let cur_time = Date.now(); let cur_time = Date.now();
if (cur_time - lastTime < MIN_TIME) //Minimum time to update not crossed: No update required if (cur_time - lastTime[asset] < MIN_TIME) //Minimum time to update not crossed: No update required
resolve(cur_rate); resolve(currentRate[asset]);
else if (noBuyOrder && noSellOrder) //Both are not available: No update required else if (noBuyOrder[asset] && noSellOrder[asset]) //Both are not available: No update required
resolve(cur_rate); resolve(currentRate[asset]);
else if (noBuyOrder === null || noSellOrder === null) //An error has occured during last process: No update (might cause price to crash/jump) else if (noBuyOrder[asset] === null || noSellOrder[asset] === null) //An error has occured during last process: No update (might cause price to crash/jump)
resolve(cur_rate); resolve(currentRate[asset]);
else else
getPastRate().then(ratePast24hr => { getPastRate(asset).then(ratePast24hr => {
if (noBuyOrder) { if (noBuyOrder[asset]) {
//No Buy, But Sell available: Decrease the price //No Buy, But Sell available: Decrease the price
let tmp_val = cur_rate * (1 - DOWN_RATE); let tmp_val = currentRate[asset] * (1 - DOWN_RATE);
if (tmp_val >= ratePast24hr * (1 - MAX_DOWN_PER_DAY)) { if (tmp_val >= ratePast24hr * (1 - MAX_DOWN_PER_DAY)) {
cur_rate = tmp_val; currentRate[asset] = tmp_val;
updateLastTime(); updateLastTime(asset);
} else } else
console.debug("Max Price down for the day has reached"); console.debug("Max Price down for the day has reached");
resolve(cur_rate); resolve(currentRate[asset]);
} else if (noSellOrder) { } else if (noSellOrder[asset]) {
//No Sell, But Buy available: Increase the price //No Sell, But Buy available: Increase the price
checkForRatedSellers().then(result => { checkForRatedSellers().then(result => {
if (result) { if (result) {
let tmp_val = cur_rate * (1 + UP_RATE); let tmp_val = currentRate[asset] * (1 + UP_RATE);
if (tmp_val <= ratePast24hr * (1 + MAX_UP_PER_DAY)) { if (tmp_val <= ratePast24hr * (1 + MAX_UP_PER_DAY)) {
cur_rate = tmp_val; currentRate[asset] = tmp_val;
updateLastTime(); updateLastTime(asset);
} else } else
console.debug("Max Price up for the day has reached"); console.debug("Max Price up for the day has reached");
} }
}).catch(error => console.error(error)).finally(_ => resolve(cur_rate)); }).catch(error => console.error(error)).finally(_ => resolve(currentRate[asset]));
} }
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
resolve(cur_rate); resolve(currentRate[asset]);
}); });
}).catch(error => reject(error)); }).catch(error => reject(error));
}) })
} }
function checkForRatedSellers() { function checkForRatedSellers(asset) {
//Check if there are best rated sellers? //Check if there are best rated sellers?
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
DB.query("SELECT MAX(sellPriority) as max_p FROM TagList").then(result => { DB.query("SELECT MAX(sellPriority) as max_p FROM TagList").then(result => {
let ratedMin = result[0].max_p * (1 - TOP_RANGE); let ratedMin = result[0].max_p * (1 - TOP_RANGE);
DB.query("SELECT COUNT(*) as value FROM SellOrder WHERE floID IN (" + DB.query("SELECT COUNT(*) as value FROM SellOrder WHERE floID IN (" +
" SELECT Tags.floID FROM Tags INNER JOIN TagList ON Tags.tag = TagList.tag" + " SELECT UserTag.floID FROM UserTag INNER JOIN TagList ON UserTag.tag = TagList.tag" +
" WHERE TagList.sellPriority > ?)", [ratedMin]).then(result => { " WHERE TagList.sellPriority > ?)", [ratedMin]).then(result => {
resolve(result[0].value > 0); resolve(result[0].value > 0);
}).catch(error => reject(error)) }).catch(error => reject(error))
@ -144,14 +152,14 @@ function checkForRatedSellers() {
module.exports = { module.exports = {
getRates, getRates,
updateLastTime, updateLastTime,
noOrder(buy, sell) { noOrder(asset, buy, sell) {
noBuyOrder = buy; noBuyOrder[asset] = buy;
noSellOrder = sell; noSellOrder[asset] = sell;
}, },
set DB(db) { set DB(db) {
DB = db; DB = db;
}, },
get currentRate() { get currentRates() {
return cur_rate return Object.assign({}, currentRate);
} }
} }

View File

@ -22,19 +22,19 @@ const oneDay = 1000 * 60 * 60 * 24;
const maxSessionTimeout = 60 * oneDay; const maxSessionTimeout = 60 * oneDay;
var serving; var serving;
const INVALID_SERVER_MSG = "Incorrect Server. Please connect to main server."; const INVALID_SERVER_MSG = "INCORRECT_SERVER_ERROR";
function validateRequestFromFloID(request, sign, floID, proxy = true) { function validateRequestFromFloID(request, sign, floID, proxy = true) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!serving) if (!serving)
return reject(INVALID(INVALID_SERVER_MSG)); return reject(INVALID(INVALID_SERVER_MSG));
else if (!floCrypto.validateAddr(floID)) else if (!floCrypto.validateAddr(floID))
return reject(INVALID.e_code).send("Invalid floID"); return reject(INVALID("Invalid floID"));
DB.query("SELECT " + (proxy ? "session_time, proxyKey AS pubKey FROM Sessions" : "pubKey FROM Users") + " WHERE floID=?", [floID]).then(result => { DB.query("SELECT " + (proxy ? "session_time, proxyKey AS pubKey FROM UserSession" : "pubKey FROM Users") + " WHERE floID=?", [floID]).then(result => {
if (result.length < 1) if (result.length < 1)
return reject(INVALID(proxy ? "Session not active" : "User not registered")); return reject(INVALID(proxy ? "Session not active" : "User not registered"));
if (proxy && result[0].session_time + maxSessionTimeout < Date.now()) if (proxy && result[0].session_time + maxSessionTimeout < Date.now())
return reject(INVALID.e_code).send("Session Expired! Re-login required"); return reject(INVALID("Session Expired! Re-login required"));
let req_str = validateRequest(request, sign, result[0].pubKey); let req_str = validateRequest(request, sign, result[0].pubKey);
req_str instanceof INVALID ? reject(req_str) : resolve(req_str); req_str instanceof INVALID ? reject(req_str) : resolve(req_str);
}).catch(error => reject(error)); }).catch(error => reject(error));
@ -62,6 +62,8 @@ function storeRequest(floID, req_str, sign) {
} }
function getLoginCode(req, res) { function getLoginCode(req, res) {
if (!serving)
return res.status(INVALID.e_code).send(INVALID_SERVER_MSG);
let randID = floCrypto.randString(8, true) + Math.round(Date.now() / 1000); let randID = floCrypto.randString(8, true) + Math.round(Date.now() / 1000);
let hash = Crypto.SHA1(randID + secret); let hash = Crypto.SHA1(randID + secret);
res.send({ res.send({
@ -111,7 +113,7 @@ function Login(req, res) {
proxyKey: data.proxyKey, proxyKey: data.proxyKey,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, data.floID, false).then(req_str => { }, data.sign, data.floID, false).then(req_str => {
DB.query("INSERT INTO Sessions (floID, proxyKey) VALUE (?, ?) AS new " + DB.query("INSERT INTO UserSession (floID, proxyKey) VALUE (?, ?) AS new " +
"ON DUPLICATE KEY UPDATE session_time=DEFAULT, proxyKey=new.proxyKey", "ON DUPLICATE KEY UPDATE session_time=DEFAULT, proxyKey=new.proxyKey",
[data.floID, data.proxyKey]).then(_ => { [data.floID, data.proxyKey]).then(_ => {
storeRequest(data.floID, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
@ -136,7 +138,7 @@ function Logout(req, res) {
type: "logout", type: "logout",
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, data.floID).then(req_str => { }, data.sign, data.floID).then(req_str => {
DB.query("DELETE FROM Sessions WHERE floID=?", [data.floID]).then(_ => { DB.query("DELETE FROM UserSession WHERE floID=?", [data.floID]).then(_ => {
storeRequest(data.floID, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send('Logout successful'); res.send('Logout successful');
}).catch(error => { }).catch(error => {
@ -157,11 +159,12 @@ function PlaceSellOrder(req, res) {
let data = req.body; let data = req.body;
validateRequestFromFloID({ validateRequestFromFloID({
type: "sell_order", type: "sell_order",
asset: data.asset,
quantity: data.quantity, quantity: data.quantity,
min_price: data.min_price, min_price: data.min_price,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, data.floID).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.addSellOrder(data.floID, data.quantity, data.min_price) market.addSellOrder(data.floID, data.asset, data.quantity, data.min_price)
.then(result => { .then(result => {
storeRequest(data.floID, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send('Sell Order placed successfully'); res.send('Sell Order placed successfully');
@ -187,11 +190,12 @@ function PlaceBuyOrder(req, res) {
let data = req.body; let data = req.body;
validateRequestFromFloID({ validateRequestFromFloID({
type: "buy_order", type: "buy_order",
asset: data.asset,
quantity: data.quantity, quantity: data.quantity,
max_price: data.max_price, max_price: data.max_price,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, data.floID).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.addBuyOrder(data.floID, data.quantity, data.max_price) market.addBuyOrder(data.floID, data.asset, data.quantity, data.max_price)
.then(result => { .then(result => {
storeRequest(data.floID, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send('Buy Order placed successfully'); res.send('Buy Order placed successfully');
@ -259,16 +263,16 @@ function ListBuyOrders(req, res) {
function ListTransactions(req, res) { function ListTransactions(req, res) {
//TODO: Limit size (recent) //TODO: Limit size (recent)
DB.query("SELECT * FROM Transactions ORDER BY tx_time DESC") DB.query("SELECT * FROM TransactionHistory ORDER BY tx_time DESC")
.then(result => res.send(result)) .then(result => res.send(result))
.catch(error => res.status(INTERNAL.e_code).send("Try again later!")); .catch(error => res.status(INTERNAL.e_code).send("Try again later!"));
} }
function getRate(req, res) { function getRates(req, res) {
if (!serving) if (!serving)
res.status(INVALID.e_code).send(INVALID_SERVER_MSG); res.status(INVALID.e_code).send(INVALID_SERVER_MSG);
else else
res.send(`${market.rate}`); res.send(market.rates);
} }
function Account(req, res) { function Account(req, res) {
@ -349,14 +353,14 @@ function WithdrawFLO(req, res) {
}); });
} }
function DepositRupee(req, res) { function DepositToken(req, res) {
let data = req.body; let data = req.body;
validateRequestFromFloID({ validateRequestFromFloID({
type: "deposit_Rupee", type: "deposit_Token",
txid: data.txid, txid: data.txid,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, data.floID).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.depositRupee(data.floID, data.txid).then(result => { market.depositToken(data.floID, data.txid).then(result => {
storeRequest(data.floID, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
@ -377,14 +381,15 @@ function DepositRupee(req, res) {
}); });
} }
function WithdrawRupee(req, res) { function WithdrawToken(req, res) {
let data = req.body; let data = req.body;
validateRequestFromFloID({ validateRequestFromFloID({
type: "withdraw_Rupee", type: "withdraw_Token",
token: data.token,
amount: data.amount, amount: data.amount,
timestamp: data.timestamp timestamp: data.timestamp
}, data.sign, data.floID).then(req_str => { }, data.sign, data.floID).then(req_str => {
market.withdrawRupee(data.floID, data.amount).then(result => { market.withdrawToken(data.floID, data.token, data.amount).then(result => {
storeRequest(data.floID, req_str, data.sign); storeRequest(data.floID, req_str, data.sign);
res.send(result); res.send(result);
}).catch(error => { }).catch(error => {
@ -479,18 +484,21 @@ module.exports = {
ListSellOrders, ListSellOrders,
ListBuyOrders, ListBuyOrders,
ListTransactions, ListTransactions,
getRate, getRates,
Account, Account,
DepositFLO, DepositFLO,
WithdrawFLO, WithdrawFLO,
DepositRupee, DepositToken,
WithdrawRupee, WithdrawToken,
periodicProcess: market.periodicProcess, periodicProcess: market.periodicProcess,
addUserTag, addUserTag,
removeUserTag, removeUserTag,
set trustedIDs(ids) { set trustedIDs(ids) {
trustedIDs = ids; trustedIDs = ids;
}, },
set assetList(assets){
market.assetList = assets;
},
set DB(db) { set DB(db) {
DB = db; DB = db;
market.DB = db; market.DB = db;

View File

@ -11,4 +11,13 @@ try {
} finally { } finally {
for (let p in param) for (let p in param)
global[p] = param[p]; global[p] = param[p];
} }
/*
//Trace the debug logs in node js
var debug = console.debug;
console.debug = function() {
debug.apply(console, arguments);
console.trace();
};
*/

View File

@ -14,7 +14,7 @@
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, },
getBalance: function(floID, token = floGlobals.token) { getBalance: function(floID, token = floGlobals.currency) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`) this.fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`)
.then(result => resolve(result.balance || 0)) .then(result => resolve(result.balance || 0))
@ -35,7 +35,7 @@
}).catch(error => reject(error)) }).catch(error => reject(error))
}) })
}, },
sendToken: function(privKey, amount, message = "", receiverID = floGlobals.adminID, token = floGlobals.token) { sendToken: function(privKey, amount, receiverID, message = "", token = floGlobals.currency) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let senderID = floCrypto.getFloID(privKey); let senderID = floCrypto.getFloID(privKey);
if (typeof amount !== "number" || amount <= 0) if (typeof amount !== "number" || amount <= 0)