diff --git a/args/schema.sql b/args/schema.sql
index 9945813..74bb07d 100644
--- a/args/schema.sql
+++ b/args/schema.sql
@@ -1,201 +1,226 @@
-/* Main Tables */
+/* Blockchain Data */
-CREATE TABLE Users (
-floID CHAR(34) NOT NULL,
-pubKey CHAR(66) NOT NULL,
-created DATETIME DEFAULT CURRENT_TIMESTAMP,
-PRIMARY KEY(floID)
+CREATE TABLE LastTx(
+ floID CHAR(34) NOT NULL,
+ num INT,
+ PRIMARY KEY(floID)
);
-CREATE TABLE Sessions (
-id INT NOT NULL AUTO_INCREMENT,
-floID CHAR(34) NOT NULL,
-proxyKey CHAR(66) NOT NULL,
-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 NodeList(
+ floID CHAR(34) NOT NULL,
+ uri TINYTEXT,
+ PRIMARY KEY(floID)
);
CREATE TABLE TagList (
-tag VARCHAR(50) NOT NULL,
-sellPriority INT,
-buyPriority INT,
-api TINYTEXT,
-PRIMARY KEY(tag)
+ tag VARCHAR(50) NOT NULL,
+ sellPriority INT,
+ buyPriority INT,
+ api TINYTEXT,
+ PRIMARY KEY(tag)
);
-CREATE TABLE Tags (
-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)
+CREATE TABLE AssetList (
+ asset VARCHAR(64) NOT NULL,
+ initialPrice FLOAT,
+ PRIMARY KEY(asset)
);
-CREATE TABLE priceHistory (
-rate FLOAT NOT NULL,
-rec_time DATETIME DEFAULT CURRENT_TIMESTAMP
+CREATE TABLE TrustedList(
+ floID CHAR(34) NOT NULL,
+ PRIMARY KEY(floID)
);
-CREATE TABLE auditTransaction(
-rec_time DATETIME DEFAULT CURRENT_TIMESTAMP,
-unit_price FLOAT NOT NULL,
-quantity FLOAT NOT NULL,
-total_cost FLOAT NOT NULL,
-sellerID CHAR(34) NOT NULL,
-FLO_seller_old FLOAT NOT NULL,
-FLO_seller_new FLOAT NOT NULL,
-Rupee_seller_old FLOAT NOT NULL,
-Rupee_seller_new FLOAT NOT NULL,
-buyerID CHAR(34) NOT NULL,
-FLO_buyer_old FLOAT NOT NULL,
-FLO_buyer_new FLOAT NOT NULL,
-Rupee_buyer_old FLOAT NOT NULL,
-Rupee_buyer_new FLOAT NOT NULL,
-FOREIGN KEY (sellerID) REFERENCES Users(floID),
-FOREIGN KEY (buyerID) REFERENCES Users(floID)
+/* User Data */
+
+CREATE TABLE Users (
+ floID CHAR(34) NOT NULL,
+ pubKey CHAR(66) NOT NULL,
+ created DATETIME DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY(floID)
+);
+
+CREATE TABLE UserSession (
+ id INT NOT NULL AUTO_INCREMENT,
+ floID CHAR(34) NOT NULL,
+ proxyKey CHAR(66) NOT NULL,
+ session_time DATETIME DEFAULT CURRENT_TIMESTAMP,
+ KEY (id),
+ PRIMARY KEY(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(
-floID CHAR(34) NOT NULL,
-share TEXT,
-time_ DATETIME DEFAULT CURRENT_TIMESTAMP,
-PRIMARY KEY(floID)
+ floID CHAR(34) NOT NULL,
+ share TEXT,
+ time_ DATETIME DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY(floID)
);
-/* Backup feature (Table and 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 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 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 TRIGGER UserSession_U AFTER UPDATE ON UserSession
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserSession', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
+CREATE TRIGGER UserSession_D AFTER DELETE ON UserSession
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserSession', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
CREATE TRIGGER Cash_I AFTER INSERT ON Cash
FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Cash', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
@@ -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
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
-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
-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
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputFLO', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
+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;
+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;
+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;
-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;
-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;
-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;
+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;
+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;
+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;
-CREATE TRIGGER inputRupee_I AFTER INSERT ON inputRupee
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputRupee', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
-CREATE TRIGGER inputRupee_U AFTER UPDATE ON inputRupee
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputRupee', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
-CREATE TRIGGER inputRupee_D AFTER DELETE ON inputRupee
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('inputRupee', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
+CREATE TRIGGER InputToken_I AFTER INSERT ON InputToken
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
+CREATE TRIGGER InputToken_U AFTER UPDATE ON InputToken
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('InputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
+CREATE TRIGGER InputToken_D AFTER DELETE ON InputToken
+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
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputRupee', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
-CREATE TRIGGER outputRupee_U AFTER UPDATE ON outputRupee
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputRupee', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
-CREATE TRIGGER outputRupee_D AFTER DELETE ON outputRupee
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('outputRupee', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
+CREATE TRIGGER OutputToken_I AFTER INSERT ON OutputToken
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
+CREATE TRIGGER OutputToken_U AFTER UPDATE ON OutputToken
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('OutputToken', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
+CREATE TRIGGER OutputToken_D AFTER DELETE ON OutputToken
+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
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Tags', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
-CREATE TRIGGER Tags_U AFTER UPDATE ON Tags
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Tags', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
-CREATE TRIGGER Tags_D AFTER DELETE ON Tags
-FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('Tags', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
\ No newline at end of file
+CREATE TRIGGER UserTag_I AFTER INSERT ON UserTag
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserTag', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
+CREATE TRIGGER UserTag_U AFTER UPDATE ON UserTag
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserTag', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT;
+CREATE TRIGGER UserTag_D AFTER DELETE ON UserTag
+FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('UserTag', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT;
\ No newline at end of file
diff --git a/args/truncateAll.sql b/args/truncateAll.sql
index da0d4a6..1d3dfed 100644
--- a/args/truncateAll.sql
+++ b/args/truncateAll.sql
@@ -1,23 +1,24 @@
/* Node data */
TRUNCATE _backup;
-TRUNCATE auditTransaction;
+TRUNCATE AuditTransaction;
TRUNCATE BuyOrder;
TRUNCATE Cash;
-TRUNCATE inputFLO;
-TRUNCATE inputRupee;
-TRUNCATE outputFLO;
-TRUNCATE outputRupee;
-TRUNCATE priceHistory;
+TRUNCATE InputFLO;
+TRUNCATE InputToken;
+TRUNCATE OutputFLO;
+TRUNCATE OutputToken;
+TRUNCATE PriceHistory;
TRUNCATE Request_Log;
TRUNCATE SellOrder;
-TRUNCATE Sessions;
-TRUNCATE Tags;
-TRUNCATE Transactions;
+TRUNCATE UserSession;
+TRUNCATE UserTag;
+TRUNCATE TransactionHistory;
TRUNCATE Vault;
TRUNCATE Users;
/* Blockchain data */
-TRUNCATE lastTx;
-TRUNCATE nodeList;
-TRUNCATE trustedList;
-TRUNCATE TagList;
\ No newline at end of file
+TRUNCATE LastTx;
+TRUNCATE NodeList;
+TRUNCATE TrustedList;
+TRUNCATE TagList;
+TRUNCATE AssetList;
\ No newline at end of file
diff --git a/public/floGlobals.js b/public/floGlobals.js
index 1153a3c..5e04811 100644
--- a/public/floGlobals.js
+++ b/public/floGlobals.js
@@ -13,7 +13,7 @@ const floGlobals = {
sendAmt: 0.001,
fee: 0.0005,
tokenURL: "https://ranchimallflo.duckdns.org/",
- token: "rupee"
+ currency: "rupee"
};
(typeof global !== "undefined" ? global : window).cryptocoin = floGlobals.blockchain;
diff --git a/public/fn.js b/public/fn.js
index f225ab0..4bdbe97 100644
--- a/public/fn.js
+++ b/public/fn.js
@@ -1,4 +1,5 @@
//console.log(document.cookie.toString());
+const INVALID_SERVER_MSG = "INCORRECT_SERVER_ERROR";
var nodeList, nodeURL, nodeKBucket; //Container for (backup) node list
function exchangeAPI(api, options) {
@@ -52,7 +53,7 @@ const tokenAPI = {
}).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) => {
let senderID = floCrypto.getFloID(privKey);
if (typeof amount !== "number" || amount <= 0)
@@ -69,7 +70,9 @@ const tokenAPI = {
}
function ResponseError(status, data) {
- if (this instanceof ResponseError) {
+ if (data === INVALID_SERVER_MSG)
+ location.reload();
+ else if (this instanceof ResponseError) {
this.data = data;
this.status = status;
} else
@@ -148,10 +151,10 @@ function getTransactionList() {
});
}
-function getRate() {
+function getRates() {
return new Promise((resolve, reject) => {
- exchangeAPI('/get-rate')
- .then(result => responseParse(result, false)
+ exchangeAPI('/get-rates')
+ .then(result => responseParse(result)
.then(result => resolve(result))
.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) => {
if (typeof quantity !== "number" || quantity <= 0)
return reject(`Invalid quantity (${quantity})`);
@@ -273,12 +276,14 @@ function buy(quantity, max_price, floID, proxySecret) {
return reject(`Invalid max_price (${max_price})`);
let request = {
floID: floID,
+ asset: asset,
quantity: quantity,
max_price: max_price,
timestamp: Date.now()
};
request.sign = signRequest({
type: "buy_order",
+ asset: asset,
quantity: quantity,
max_price: max_price,
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) => {
if (typeof quantity !== "number" || quantity <= 0)
return reject(`Invalid quantity (${quantity})`);
@@ -307,6 +312,7 @@ function sell(quantity, min_price, floID, proxySecret) {
return reject(`Invalid min_price (${min_price})`);
let request = {
floID: floID,
+ asset: asset,
quantity: quantity,
min_price: min_price,
timestamp: Date.now()
@@ -314,6 +320,7 @@ function sell(quantity, min_price, floID, proxySecret) {
request.sign = signRequest({
type: "sell_order",
quantity: quantity,
+ asset: asset,
min_price: min_price,
timestamp: request.timestamp
}, proxySecret);
@@ -376,7 +383,7 @@ function depositFLO(quantity, floID, sinkID, privKey, proxySecret) {
};
request.sign = signRequest({
type: "deposit_FLO",
- txid: request.txid,
+ txid: txid,
timestamp: request.timestamp
}, proxySecret);
console.debug(request);
@@ -404,7 +411,7 @@ function withdrawFLO(quantity, floID, proxySecret) {
};
request.sign = signRequest({
type: "withdraw_FLO",
- amount: request.amount,
+ amount: quantity,
timestamp: request.timestamp
}, proxySecret);
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) => {
if (!floCrypto.verifyPrivKey(privKey, floID))
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 = {
floID: floID,
txid: txid,
timestamp: Date.now()
};
request.sign = signRequest({
- type: "deposit_Rupee",
- txid: request.txid,
+ type: "deposit_Token",
+ txid: txid,
timestamp: request.timestamp
}, proxySecret);
console.debug(request);
- exchangeAPI('/deposit-rupee', {
+ exchangeAPI('/deposit-token', {
method: "POST",
headers: {
'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) => {
let request = {
floID: floID,
+ token: token,
amount: quantity,
timestamp: Date.now()
};
request.sign = signRequest({
- type: "withdraw_Rupee",
- amount: request.amount,
+ type: "withdraw_Token",
+ token: token,
+ amount: quantity,
timestamp: request.timestamp
}, proxySecret);
console.debug(request);
- exchangeAPI('/withdraw-rupee', {
+ exchangeAPI('/withdraw-token', {
method: "POST",
headers: {
'Content-Type': 'application/json'
@@ -490,8 +499,8 @@ function addUserTag(tag_user, tag, floID, proxySecret) {
};
request.sign = signRequest({
command: "add_Tag",
- user: request.user,
- tag: request.tag,
+ user: tag_user,
+ tag: tag,
timestamp: request.timestamp
}, proxySecret);
console.debug(request);
@@ -519,8 +528,8 @@ function removeUserTag(tag_user, tag, floID, proxySecret) {
};
request.sign = signRequest({
command: "remove_Tag",
- user: request.user,
- tag: request.tag,
+ user: tag_user,
+ tag: tag,
timestamp: request.timestamp
}, proxySecret);
console.debug(request);
diff --git a/public/home.html b/public/home.html
index c02e190..81855d7 100644
--- a/public/home.html
+++ b/public/home.html
@@ -102,6 +102,7 @@
Sell
+
@@ -976,23 +977,23 @@
}
const render = {
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
card.dataset.id = id
card.dataset.type = 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').textContent = formatAmount(price)
card.querySelector('.order-card__time').textContent = getFormattedTime(time, true)
return card
},
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
card.dataset.type = 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__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2)))
card.querySelector('.more-info').dataset.buyer = buyer
@@ -1002,12 +1003,12 @@
return card
},
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
card.dataset.type = type
card.classList.add(`transaction-card--${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__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2)))
card.querySelector('.more-info').dataset.time = time
@@ -1017,9 +1018,9 @@
return card
},
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
- 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__total').textContent = formatAmount(parseFloat((unitValue * quantity).toFixed(2)))
card.querySelector('.more-info').dataset.time = time
@@ -1047,14 +1048,15 @@
getRef('quantity_type').textContent = tradeType === 'buy' ? `Rupee` : `FLO`
})
async function tradeFlo() {
+ const asset = getRef('get_asset').value;
const quantity = parseFloat(getRef('get_quantity').value)
const price = parseFloat(getRef('get_price').value)
showProcess('trade_button_wrapper')
try {
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 {
- 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))
notify(`Placed ${tradeType} order`, 'success')
@@ -1197,14 +1199,14 @@
if (asset === 'FLO') {
await depositFLO(quantity, proxy.userID, proxy.sinkID, privKey, proxySecret)
} 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.')
} else {
if (asset === 'FLO') {
await withdrawFLO(quantity, proxy.userID, proxySecret)
} 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.')
}
@@ -1422,9 +1424,10 @@
if (ordersType === 'open') {
const allOpenOrders = [...buyOrders, ...sellOrders].sort((a, b) => new Date(b.time_placed).getTime() - new Date(a.time_placed).getTime())
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 = {
id,
+ asset,
quantity,
type: minPrice ? 'sell' : 'buy',
price: minPrice || maxPrice,
@@ -1434,7 +1437,7 @@
})
} else {
transactions.forEach(transaction => {
- const { quantity, unitValue, tx_time, buyer, seller } = transaction
+ const {asset, quantity, unitValue, tx_time, buyer, seller } = transaction
let type, other;
if (seller === proxy.userID) {
type = 'Sold';
@@ -1449,6 +1452,7 @@
seller,
type,
other,
+ asset,
quantity,
unitValue,
time: tx_time
@@ -1470,9 +1474,10 @@
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())
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 = {
floID,
+ asset,
quantity,
type: minPrice ? 'sell' : 'buy',
unitValue: minPrice || maxPrice,
@@ -1488,10 +1493,11 @@
try {
const marketTransactions = await getTransactionList()
marketTransactions.forEach(transaction => {
- const { seller, buyer, quantity, unitValue, tx_time } = transaction
+ const { seller, buyer, asset, quantity, unitValue, tx_time } = transaction
const transactionDetails = {
buyer,
seller,
+ asset,
quantity,
unitValue,
time: tx_time
@@ -1554,14 +1560,14 @@
notify("Password minimum length is 4", 'error');
else {
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');
}
}).catch(_ => null);
},
clear() {
- localStorage.removeItem("proxy_secret");
- localStorage.removeItem("user_ID");
+ localStorage.removeItem("exchange-proxy_secret");
+ localStorage.removeItem("exchange-user_ID");
this.user = null;
this.private = null;
this.public = null;
@@ -1570,19 +1576,19 @@
return getRef("sink_id").value;
},
set userID(id){
- localStorage.setItem("user_ID", id);
+ localStorage.setItem("exchange-user_ID", id);
this.user = id;
},
get userID(){
if(this.user)
return this.user;
else{
- let id = localStorage.getItem('user_ID');
+ let id = localStorage.getItem('exchange-user_ID');
return id ? this.user = id : undefined;
}
},
set secret(key) {
- localStorage.setItem("proxy_secret", key);
+ localStorage.setItem("exchange-proxy_secret", key);
this.private = key;
this.public = floCrypto.getPubKeyHex(key);
},
@@ -1605,7 +1611,7 @@
Reject("Unable to fetch Proxy secret");
}
};
- let tmp = localStorage.getItem("proxy_secret");
+ let tmp = localStorage.getItem("exchange-proxy_secret");
if (typeof tmp !== "string")
Reject("Unable to fetch Proxy secret");
else if (tmp.startsWith("?")) {
@@ -1629,11 +1635,21 @@
}
let floExchangeRate = 0
- function updateRate() {
- getRate().then(rate => {
- floExchangeRate = parseFloat(rate)
- getRef('flo_rate').textContent = formatAmount(parseFloat(rate))
- getRef('get_price').value = parseFloat(parseFloat(rate).toFixed(2))
+ function updateRate(init = false) {
+ getRates().then(rates => {
+ console.debug(rates);
+ if(init){
+ 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))
}
@@ -1652,7 +1668,7 @@
}
} else
console.info("refresh");
- updateRate();
+ updateRate(init);
renderMarketOrders();
if(proxy.userID)
account();
@@ -1686,7 +1702,8 @@
getRef("user_id").value = acc.floID;
getRef("sink_id").value = acc.sinkID;
//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_net = flo_total - flo_locked;
console.debug("FLO", flo_total, flo_locked, flo_net);
@@ -1694,7 +1711,7 @@
showBalance("flo", flo_net, flo_locked,)
//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_net = rupee_total - rupee_locked;
console.debug("RUPEE", rupee_total, rupee_locked, rupee_net);
diff --git a/src/app.js b/src/app.js
index cc05e06..ce01d54 100644
--- a/src/app.js
+++ b/src/app.js
@@ -4,7 +4,7 @@ const express = require('express');
//const sessions = require('express-session');
const Request = require('./request');
-const REFRESH_INTERVAL = 5 * 1000; //10 * 60 * 1000;
+const REFRESH_INTERVAL = 1 * 60 * 1000;
module.exports = function App(secret, DB) {
@@ -72,7 +72,7 @@ module.exports = function App(secret, DB) {
//list all process transactions and rate
app.get('/list-transactions', Request.ListTransactions);
- app.get('/get-rate', Request.getRate)
+ app.get('/get-rates', Request.getRates)
//get account details
app.post('/account', Request.Account);
@@ -80,8 +80,8 @@ module.exports = function App(secret, DB) {
//withdraw and deposit request
app.post('/deposit-flo', Request.DepositFLO);
app.post('/withdraw-flo', Request.WithdrawFLO);
- app.post('/deposit-rupee', Request.DepositRupee);
- app.post('/withdraw-rupee', Request.WithdrawRupee);
+ app.post('/deposit-token', Request.DepositToken);
+ app.post('/withdraw-token', Request.WithdrawToken);
//Manage user tags (Access to trusted IDs only)
@@ -108,6 +108,10 @@ module.exports = function App(secret, DB) {
set: (ids) => Request.trustedIDs = ids
});
+ Object.defineProperty(self, "assetList", {
+ set: (assets) => Request.assetList = assets
+ });
+
//Start (or) Stop servers
self.start = (port) => new Promise(resolve => {
server = app.listen(port, () => {
diff --git a/src/backup/head.js b/src/backup/head.js
index e0f3afb..d924c25 100644
--- a/src/backup/head.js
+++ b/src/backup/head.js
@@ -5,7 +5,7 @@ const slave = require('./slave');
const WebSocket = require('ws');
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 nodeShares = null,
nodeSinkID = null,
@@ -104,8 +104,8 @@ function send_dataImmutable(timestamp, ws) {
const immutable_tables = {
Users: "created",
Request_Log: "request_time",
- Transactions: "tx_time",
- priceHistory: "rec_time"
+ TransactionHistory: "tx_time",
+ PriceHistory: "rec_time"
};
const sendTable = (table, timeCol) => new Promise((res, rej) => {
DB.query(`SELECT * FROM ${table} WHERE ${timeCol} > ?`, [timestamp])
@@ -175,16 +175,36 @@ function storeSink(sinkID, sinkPrivKey) {
.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) => {
- let newSink = generateNewSink();
- floBlockchainAPI.getBalance(oldSinkID).then(balFLO => {
- tokenAPI.getBalance(oldSinkID).then(balRupee => {
- floBlockchainAPI.sendTx(oldSinkID, newSink.floID, balFLO - floGlobals.fee, oldSinkKey, `send ${balRupee} ${floGlobals.token}# |Exchange-market New sink`)
- .then(result => resolve(newSink))
- .catch(error => reject(error))
- }).catch(error => reject(error));
- }).catch(error => reject(error))
+ console.debug("Transferring tokens to new Sink:", newSink.floID)
+ Promise.allSettled(tokenList.map(token => transferToken(token))).then(result => {
+ let failedFlag = false;
+ tokenList.forEach((token, i) => {
+ if (result[i].status === "fulfilled")
+ console.log(token, result[i].value);
+ else {
+ 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");
collectShares.shares[floID] = share;
try {
- let privKey = floCrypto.retrieveShamirSecret(Object.values(collectShares.shares));
- if (floCrypto.verifyPrivKey(privKey, collectShares.sinkID)) {
- transferMoneyToNewSink(collectShares.sinkID, privKey).then(newSink => {
- delete collectShares.sinkID;
- delete collectShares.shares;
- collectShares.active = false;
- storeSink(newSink.floID, newSink.privKey);
- sendSharesToNodes(newSink.floID, newSink.shares);
- }).catch(error => console.error(error));
+ let oldSinkKey = floCrypto.retrieveShamirSecret(Object.values(collectShares.shares));
+ if (floCrypto.verifyPrivKey(oldSinkKey, collectShares.sinkID)) {
+ let newSink = generateNewSink();
+ transferMoneyToNewSink(collectShares.sinkID, oldSinkKey, newSink).then(result => {
+ console.log("Money transfer successful", result);
+ delete collectShares.sinkID;
+ delete collectShares.shares;
+ collectShares.active = false;
+ sendSharesToNodes(newSink.floID, newSink.shares);
+ }).catch(error => console.error(error))
+ .finally(_ => storeSink(newSink.floID, newSink.privKey));
}
} catch (error) {
//Unable to retrive sink private key. Waiting for more shares! Do nothing for now
@@ -391,6 +413,9 @@ module.exports = {
nodeList = nodeKBucket.order;
console.debug(nodeList);
},
+ set assetList(assets) {
+ tokenList = assets.filter(a => a.toUpperCase() !== "FLO");
+ },
set DB(db) {
DB = db;
slave.DB = db;
diff --git a/src/backup/slave.js b/src/backup/slave.js
index ed670c0..51d9818 100644
--- a/src/backup/slave.js
+++ b/src/backup/slave.js
@@ -32,6 +32,7 @@ function stopSlaveProcess() {
if (masterWS !== null) {
masterWS.onclose = () => null;
masterWS.close();
+ requestInstance.close();
masterWS = null;
}
if (intervalID !== null) {
@@ -45,8 +46,8 @@ function requestBackupSync(ws) {
const tables = {
Users: "created",
Request_Log: "request_time",
- Transactions: "tx_time",
- //priceHistory: "rec_time",
+ TransactionHistory: "tx_time",
+ //PriceHistory: "rec_time",
_backup: "timestamp"
};
let subs = [];
@@ -161,6 +162,9 @@ function sendSinkShare() {
}
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;
self.last_response_time = Date.now();
switch (response.command) {
diff --git a/src/coupling.js b/src/coupling.js
index 72099bd..67c2f53 100644
--- a/src/coupling.js
+++ b/src/coupling.js
@@ -5,9 +5,9 @@ const price = require("./price");
var DB; //container for database
-function initiate() {
- price.getRates().then(cur_rate => {
- group.getBestPairs(cur_rate)
+function startCouplingForAsset(asset) {
+ price.getRates(asset).then(cur_rate => {
+ group.getBestPairs(asset, cur_rate)
.then(bestPairQueue => processCoupling(bestPairQueue))
.catch(error => console.error("initiateCoupling", error))
}).catch(error => console.error(error));
@@ -19,17 +19,21 @@ function processCoupling(bestPairQueue) {
seller_best = pair_result.sellOrder;
console.debug("Sell:", seller_best);
console.debug("Buy:", buyer_best);
- spendFLO(buyer_best, seller_best, pair_result.null_base).then(spend_result => {
- let tx_quantity = spend_result.quantity,
- txQueries = spend_result.txQueries,
- clear_sell = spend_result.incomplete && !spend_result.flag_baseNull; //clear_sell can be true only if an order is placed without enough FLO
- processOrders(seller_best, buyer_best, txQueries, tx_quantity, clear_sell);
- updateBalance(seller_best, buyer_best, txQueries, bestPairQueue.cur_rate, tx_quantity);
+ spendAsset(bestPairQueue.asset, buyer_best, seller_best, pair_result.null_base).then(spent => {
+ if (!spent.quantity) {
+ //Happens when there are only Null-base assets
+ bestPairQueue.next(spent.quantity, spent.incomplete);
+ processCoupling(bestPairQueue);
+ return;
+ }
+ let txQueries = spent.txQueries;
+ processOrders(seller_best, buyer_best, txQueries, spent.quantity, spent.incomplete && pair_result.null_base);
+ updateBalance(seller_best, buyer_best, txQueries, bestPairQueue.asset, bestPairQueue.cur_rate, spent.quantity);
//begin audit
- beginAudit(seller_best.floID, buyer_best.floID, bestPairQueue.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
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}`);
audit.end();
price.updateLastTime();
@@ -46,7 +50,7 @@ function processCoupling(bestPairQueue) {
console.error(error.buy);
noBuy = null;
} else {
- console.log("No valid buyOrders.");
+ console.log("No valid buyOrders for Asset:", bestPairQueue.asset);
noBuy = true;
}
if (error.sell === undefined)
@@ -55,35 +59,31 @@ function processCoupling(bestPairQueue) {
console.error(error.sell);
noSell = null;
} else {
- console.log("No valid sellOrders.");
+ console.log("No valid sellOrders for Asset:", bestPairQueue.asset);
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) => {
- 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),
- txQueries = [],
- flag_baseNull = false;
+ txQueries = [];
for (let i = 0; i < result.length && rem > 0; i++)
- if (result[i].base || null_base) {
- if (rem < result[i].quantity) {
- txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]);
- rem = 0;
- } else {
- txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]);
- rem -= result[i].quantity;
- }
- } else
- flag_baseNull = true;
+ if (rem < result[i].quantity) {
+ txQueries.push(["UPDATE Vault SET quantity=quantity-? WHERE id=?", [rem, result[i].id]]);
+ rem = 0;
+ } else {
+ txQueries.push(["DELETE FROM Vault WHERE id=?", [result[i].id]]);
+ rem -= result[i].quantity;
+ }
resolve({
quantity: Math.min(buyOrder.quantity, sellOrder.quantity) - rem,
txQueries,
- incomplete: rem > 0,
- flag_baseNull
+ incomplete: rem > 0
});
}).catch(error => reject(error));
})
@@ -98,55 +98,56 @@ function processOrders(seller_best, buyer_best, txQueries, quantity, clear_sell)
else
txQueries.push(["UPDATE BuyOrder SET quantity=quantity-? WHERE id=?", [quantity, buyer_best.id]]);
//Process Sell Order
- if (quantity == seller_best.quantity || clear_sell)
+ 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]]);
else
txQueries.push(["UPDATE SellOrder SET quantity=quantity-? WHERE id=?", [quantity, seller_best.id]]);
}
-function updateBalance(seller_best, buyer_best, txQueries, cur_price, quantity) {
- //Update rupee balance for seller and buyer
+function updateBalance(seller_best, buyer_best, txQueries, asset, cur_price, quantity) {
+ //Update cash balance for seller and buyer
let totalAmount = cur_price * quantity;
- txQueries.push(["UPDATE Cash SET rupeeBalance=rupeeBalance+? 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, seller_best.floID]]);
+ txQueries.push(["UPDATE Cash SET balance=balance-? WHERE floID=?", [totalAmount, buyer_best.floID]]);
//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
- 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) => {
- auditBalance(sellerID, buyerID).then(old_bal => resolve({
- end: () => endAudit(sellerID, buyerID, old_bal, unit_price, quantity)
+ auditBalance(sellerID, buyerID, asset).then(old_bal => resolve({
+ end: () => endAudit(sellerID, buyerID, asset, old_bal, unit_price, quantity)
})).catch(error => reject(error))
})
}
-function endAudit(sellerID, buyerID, old_bal, unit_price, quantity) {
- auditBalance(sellerID, buyerID).then(new_bal => {
- DB.query("INSERT INTO auditTransaction (sellerID, buyerID, quantity, unit_price, total_cost, " +
- " Rupee_seller_old, Rupee_seller_new, Rupee_buyer_old, Rupee_buyer_new," +
- " FLO_seller_old, FLO_seller_new, FLO_buyer_old, FLO_buyer_new) " +
- " Value (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [sellerID, buyerID, quantity, unit_price, quantity * unit_price,
- old_bal[sellerID].Rupee, new_bal[sellerID].Rupee, old_bal[buyerID].Rupee, new_bal[buyerID].Rupee,
- old_bal[sellerID].FLO, new_bal[sellerID].FLO, old_bal[buyerID].FLO, new_bal[buyerID].FLO,
+function endAudit(sellerID, buyerID, asset, old_bal, unit_price, quantity) {
+ auditBalance(sellerID, buyerID, asset).then(new_bal => {
+ DB.query("INSERT INTO AuditTransaction (asset, quantity, unit_price, total_cost," +
+ " sellerID, seller_old_cash, seller_old_asset, seller_new_cash, seller_new_asset," +
+ " buyerID, buyer_old_cash, buyer_old_asset, buyer_new_cash, buyer_new_asset)" +
+ " Value (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [
+ asset, quantity, unit_price, quantity * unit_price,
+ 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))
}).catch(error => console.error(error));
}
-function auditBalance(sellerID, buyerID) {
+function auditBalance(sellerID, buyerID, asset) {
return new Promise((resolve, reject) => {
let balance = {
[sellerID]: {},
[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)
- balance[result[i].floID].Rupee = result[i].rupeeBalance;
- DB.query("SELECT floID, SUM(quantity) as floBal FROM Vault WHERE floID IN (?, ?) GROUP BY floID", [sellerID, buyerID]).then(result => {
+ balance[result[i].floID].cash = result[i].balance;
+ DB.query("SELECT floID, SUM(quantity) as asset_balance FROM Vault WHERE asset=? AND floID IN (?, ?) GROUP BY floID", [asset, sellerID, buyerID]).then(result => {
for (let i in result)
- balance[result[i].floID].FLO = result[i].floBal;
+ balance[result[i].floID].asset = result[i].asset_balance;
resolve(balance);
}).catch(error => reject(error))
}).catch(error => reject(error))
@@ -154,8 +155,11 @@ function auditBalance(sellerID, buyerID) {
}
module.exports = {
- initiate,
- group,
+ initiate: startCouplingForAsset,
+ group: {
+ addTag: group.addTag,
+ removeTag: group.removeTag
+ },
price,
set DB(db) {
DB = db;
diff --git a/src/group.js b/src/group.js
index 03d402b..9888866 100644
--- a/src/group.js
+++ b/src/group.js
@@ -4,7 +4,7 @@ var DB; //container for database
function addTag(floID, tag) {
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}`))
.catch(error => {
if (error.code === "ER_DUP_ENTRY")
@@ -19,28 +19,31 @@ function addTag(floID, tag) {
function removeTag(floID, tag) {
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}`))
.catch(error => reject(error));
})
}
-function getBestPairs(currentRate) {
+function getBestPairs(asset, cur_rate) {
return new Promise((resolve, reject) => {
DB.query("SELECT tag, sellPriority, buyPriority FROM TagList").then(result => {
//Sorted in Ascending (ie, stack; pop for highest)
let tags_buy = result.sort((a, b) => a.buyPriority > b.buyPriority ? 1 : -1).map(r => r.tag);
let tags_sell = result.sort((a, b) => a.sellPriority > b.sellPriority ? 1 : -1).map(r => r.tag);
- resolve(new bestPair(currentRate, tags_buy, tags_sell));
+ resolve(new bestPair(asset, cur_rate, tags_buy, tags_sell));
}).catch(error => reject(error))
})
}
-const bestPair = function(cur_rate, tags_buy, tags_sell) {
- const currentRate = cur_rate;
+const bestPair = function(asset, cur_rate, tags_buy, tags_sell) {
+
+ Object.defineProperty(this, 'asset', {
+ get: () => asset
+ });
Object.defineProperty(this, 'cur_rate', {
- get: () => currentRate
+ get: () => cur_rate,
});
this.get = () => new Promise((resolve, reject) => {
@@ -59,7 +62,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
}).catch(error => reject(error))
});
- this.next = (tx_quantity, incomplete_sell, flag_sell) => {
+ this.next = (tx_quantity, incomplete_sell) => {
let buy = getBuyOrder.cache,
sell = getSellOrder.cache;
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) {
sell.cur_order.quantity -= tx_quantity;
if (incomplete_sell) {
- if (!sell.mode_null && flag_sell)
+ if (!sell.mode_null)
sell.null_queue.push(sell.cur_order);
sell.cur_order = null;
}
@@ -89,7 +92,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
const getSellOrder = () => new Promise((resolve, reject) => {
let cache = getSellOrder.cache;
if (cache.cur_order) { //If cache already has a pending order
- verifySellOrder(cache.cur_order, currentRate, cache.mode_null).then(result => {
+ verifySellOrder(cache.cur_order, asset, cur_rate, cache.mode_null).then(result => {
cache.cur_order = result;
resolve(result);
}).catch(error => {
@@ -102,7 +105,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
.catch(error => reject(error))
})
} 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;
resolve(result);
}).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
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;
getSellOrder()
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error));
} else if (!cache.end) { //Un-tagged floID's orders (do only once)
- getUntaggedSellOrders(currentRate).then(orders => {
+ getUntaggedSellOrders(asset, cur_rate).then(orders => {
cache.orders = orders;
cache.cur_tag = null;
cache.end = true;
@@ -131,7 +134,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
.then(result => resolve(result))
.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.mode_null = true;
cache.null_queue = null;
@@ -150,7 +153,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
const getBuyOrder = () => new Promise((resolve, reject) => {
let cache = getBuyOrder.cache;
if (cache.cur_order) { //If cache already has a pending order
- verifyBuyOrder(cache.cur_order, currentRate).then(result => {
+ verifyBuyOrder(cache.cur_order, cur_rate).then(result => {
cache.cur_order = result;
resolve(result);
}).catch(error => {
@@ -163,7 +166,7 @@ const bestPair = function(cur_rate, tags_buy, tags_sell) {
.catch(error => reject(error))
})
} 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;
resolve(result);
}).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
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;
getBuyOrder()
.then(result => resolve(result))
.catch(error => reject(error))
}).catch(error => reject(error));
} else if (!cache.end) { //Un-tagged floID's orders (do only once)
- getUntaggedBuyOrders(currentRate).then(orders => {
+ getUntaggedBuyOrders(asset, cur_rate).then(orders => {
cache.orders = orders;
cache.cur_tag = null;
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) => {
DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity FROM SellOrder" +
- " LEFT JOIN Tags ON Tags.floID = SellOrder.floID" +
- " WHERE Tags.floID IS NULL AND SellOrder.minPrice <=? ORDER BY SellOrder.time_placed DESC", [cur_price])
+ " LEFT JOIN UserTag ON UserTag.floID = SellOrder.floID" +
+ " WHERE UserTag.floID IS NULL AND SellOrder.asset = ? AND SellOrder.minPrice <=?" +
+ " ORDER BY SellOrder.time_placed DESC", [asset, cur_price])
.then(orders => resolve(orders))
.catch(error => reject(error))
})
}
-function getUntaggedBuyOrders(cur_price) {
+function getUntaggedBuyOrders(asset, cur_price) {
return new Promise((resolve, reject) => {
DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" +
- " LEFT JOIN Tags ON Tags.floID = BuyOrder.floID" +
- " WHERE Tags.floID IS NULL AND BuyOrder.maxPrice >=? ORDER BY BuyOrder.time_placed DESC", [cur_price])
+ " LEFT JOIN UserTag ON UserTag.floID = BuyOrder.floID" +
+ " WHERE UserTag.floID IS NULL AND BuyOrder.asset = ? AND BuyOrder.maxPrice >=? " +
+ " ORDER BY BuyOrder.time_placed DESC", [asset, cur_price])
.then(orders => resolve(orders))
.catch(error => reject(error))
})
}
-function getSellOrdersInTag(tag, cur_price) {
+function getSellOrdersInTag(tag, asset, cur_price) {
return new Promise((resolve, reject) => {
DB.query("SELECT SellOrder.id, SellOrder.floID, SellOrder.quantity FROM SellOrder" +
- " INNER JOIN Tags ON Tags.floID = SellOrder.floID" +
- " WHERE Tags.tag = ? AND SellOrder.minPrice <=? ORDER BY SellOrder.time_placed DESC", [tag, cur_price]).then(orders => {
+ " INNER JOIN UserTag ON UserTag.floID = SellOrder.floID" +
+ " 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.
resolve(orders);
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) => {
DB.query("SELECT BuyOrder.id, BuyOrder.floID, BuyOrder.quantity FROM BuyOrder" +
- " INNER JOIN Tags ON Tags.floID = BuyOrder.floID" +
- " WHERE Tags.tag = ? AND BuyOrder.maxPrice >=? ORDER BY BuyOrder.time_placed DESC", [tag, cur_price]).then(orders => {
+ " INNER JOIN UserTag ON UserTag.floID = BuyOrder.floID" +
+ " 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.
resolve(orders);
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) => {
if (!orders.length)
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))
.catch(error => {
if (error !== false)
return reject(error);
- getTopValidSellOrder(orders, cur_price, mode_null)
+ getTopValidSellOrder(orders, asset, cur_price, mode_null)
.then(result => resolve(result))
.catch(error => reject(error));
});
});
}
-function verifySellOrder(sellOrder, cur_price, mode_null) {
+function verifySellOrder(sellOrder, asset, cur_price, mode_null) {
return new Promise((resolve, reject) => {
if (!mode_null)
- DB.query("SELECT quantity, base FROM Vault WHERE floID=? AND 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,
sell_base = 0,
base_quantity = 0;
@@ -329,10 +336,10 @@ function verifySellOrder(sellOrder, cur_price, mode_null) {
resolve(sellOrder);
}).catch(error => reject(error));
else if (mode_null)
- DB.query("SELECT SUM(quantity) as total FROM Vault WHERE floID=?", [sellOrder.floID]).then(result => {
- if (result.total < sellOrder.quantity)
- console.warn(`Sell Order ${sellOrder.id} was made without enough FLO. This should not happen`);
- if (result.total > 0)
+ DB.query("SELECT SUM(quantity) as total FROM Vault WHERE floID=? AND asset=?", [sellOrder.floID, asset]).then(result => {
+ if (result[0].total < sellOrder.quantity)
+ console.warn(`Sell Order ${sellOrder.id} was made without enough Assets. This should not happen`);
+ if (result[0].total > 0)
resolve(sellOrder);
else
reject(false);
@@ -358,10 +365,10 @@ function getTopValidBuyOrder(orders, cur_price) {
function verifyBuyOrder(buyOrder, cur_price) {
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) {
- //This should not happen unless a buy order is placed when user doesnt have enough rupee balance
- console.warn(`Buy order ${buyOrder.id} is active, but rupee# is insufficient`);
+ //This should not happen unless a buy order is placed when user doesnt have enough cash balance
+ console.warn(`Buy order ${buyOrder.id} is active, but Cash is insufficient`);
reject(false);
} else
resolve(buyOrder);
diff --git a/src/main.js b/src/main.js
index 42a2b73..fbd3758 100644
--- a/src/main.js
+++ b/src/main.js
@@ -25,7 +25,7 @@ function refreshData(startup = false) {
function refreshDataFromBlockchain() {
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;
floBlockchainAPI.readData(floGlobals.adminID, {
ignoreOld: lastTx,
@@ -34,6 +34,7 @@ function refreshDataFromBlockchain() {
}).then(result => {
let promises = [],
nodes_change = false,
+ assets_change = false,
trusted_change = false;
result.data.reverse().forEach(data => {
var content = JSON.parse(data)[floGlobals.application];
@@ -42,20 +43,26 @@ function refreshDataFromBlockchain() {
nodes_change = true;
if (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)
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
if (content.Trusted) {
trusted_change = true;
if (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)
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
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(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
Promise.allSettled(promises).then(results => {
console.debug(results.filter(r => r.status === "rejected"));
@@ -80,6 +87,7 @@ function refreshDataFromBlockchain() {
});
resolve({
nodes: nodes_change,
+ assets: assets_change,
trusted: trusted_change
});
}).catch(error => reject(error));
@@ -92,6 +100,8 @@ function loadDataFromDB(changes, startup) {
let promises = [];
if (startup || changes.nodes)
promises.push(loadDataFromDB.nodeList());
+ if (startup || changes.assets)
+ promises.push(loadDataFromDB.assetList());
if (startup || changes.trusted)
promises.push(loadDataFromDB.trustedIDs());
Promise.all(promises)
@@ -102,7 +112,7 @@ function loadDataFromDB(changes, startup) {
loadDataFromDB.nodeList = function() {
return new Promise((resolve, reject) => {
- DB.query("SELECT * FROM nodeList").then(result => {
+ DB.query("SELECT floID, uri FROM NodeList").then(result => {
let nodes = {}
for (let i in result)
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() {
return new Promise((resolve, reject) => {
- DB.query("SELECT * FROM trustedList").then(result => {
+ DB.query("SELECT * FROM TrustedList").then(result => {
let trustedIDs = [];
for (let i in result)
trustedIDs.push(result[i].floID);
diff --git a/src/market.js b/src/market.js
index 1458959..8758940 100644
--- a/src/market.js
+++ b/src/market.js
@@ -3,9 +3,59 @@
const coupling = require('./coupling');
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) => {
if (!floID || !floCrypto.validateAddr(floID))
return reject(INVALID("Invalid FLO ID"));
@@ -13,41 +63,33 @@ function addSellOrder(floID, quantity, min_price) {
return reject(INVALID(`Invalid quantity (${quantity})`));
else if (typeof min_price !== "number" || min_price <= 0)
return reject(INVALID(`Invalid min_price (${min_price})`));
- checkSellRequirement(floID).then(_ => {
- DB.query("SELECT SUM(quantity) AS total FROM Vault WHERE floID=?", [floID]).then(result => {
- let total = result.pop()["total"] || 0;
- if (total < quantity)
- return reject(INVALID("Insufficient FLO"));
- DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=?", [floID]).then(result => {
- let locked = result.pop()["locked"] || 0;
- let available = total - locked;
- 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));
+ else if (!assetList.includes(asset))
+ return reject(INVALID(`Invalid asset (${asset})`));
+ getAssetBalance.check(floID, asset, quantity).then(_ => {
+ checkSellRequirement(floID).then(_ => {
+ DB.query("INSERT INTO SellOrder(floID, asset, quantity, minPrice) VALUES (?, ?, ?, ?)", [floID, asset, quantity, min_price])
+ .then(result => resolve("Added SellOrder to DB"))
+ .catch(error => reject(error));
+ }).catch(error => reject(error))
}).catch(error => reject(error));
});
}
-function checkSellRequirement(floID) {
- return new Promise((resolve, reject) => {
- DB.query("SELECT * FROM Tags WHERE floID=? AND tag=?", [floID, "MINER"]).then(result => {
- if (result.length)
- return resolve(true);
- DB.query("SELECT SUM(quantity) AS brought FROM Transactions WHERE buyer=?", [floID]).then(result => {
- if (result[0].brought >= MINIMUM_BUY_REQUIREMENT)
- resolve(true);
- else
- 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))
+const checkSellRequirement = floID => new Promise((resolve, reject) => {
+ DB.query("SELECT * FROM UserTag WHERE floID=? AND tag=?", [floID, "MINER"]).then(result => {
+ if (result.length)
+ return resolve(true);
+ //TODO: Should seller need to buy same type of asset before selling?
+ DB.query("SELECT SUM(quantity) AS brought FROM TransactionHistory WHERE buyer=?", [floID]).then(result => {
+ if (result[0].brought >= MINIMUM_BUY_REQUIREMENT)
+ resolve(true);
+ else
+ 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))
+});
-function addBuyOrder(floID, quantity, max_price) {
+function addBuyOrder(floID, asset, quantity, max_price) {
return new Promise((resolve, reject) => {
if (!floID || !floCrypto.validateAddr(floID))
return reject(INVALID("Invalid FLO ID"));
@@ -55,21 +97,12 @@ function addBuyOrder(floID, quantity, max_price) {
return reject(INVALID(`Invalid quantity (${quantity})`));
else if (typeof max_price !== "number" || max_price <= 0)
return reject(INVALID(`Invalid max_price (${max_price})`));
- DB.query("SELECT rupeeBalance FROM Cash WHERE floID=?", [floID]).then(result => {
- if (result.length < 1)
- return reject(INVALID("FLO ID not registered"));
- let total = result.pop()["rupeeBalance"];
- if (total < quantity * max_price)
- return reject(INVALID("Insufficient Rupee balance"));
- 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));
+ else if (!assetList.includes(asset))
+ return reject(INVALID(`Invalid asset (${asset})`));
+ getAssetBalance.check(floID, asset, quantity).then(_ => {
+ DB.query("INSERT INTO BuyOrder(floID, asset, quantity, maxPrice) VALUES (?, ?, ?, ?)", [floID, asset, quantity, max_price])
+ .then(result => resolve("Added BuyOrder to DB"))
+ .catch(error => reject(error));
}).catch(error => reject(error));
});
}
@@ -101,11 +134,11 @@ function cancelOrder(type, id, floID) {
function getAccountDetails(floID) {
return new Promise((resolve, reject) => {
let select = [];
- select.push(["rupeeBalance", "Cash"]);
- select.push(["base, quantity", "Vault"]);
- select.push(["id, quantity, minPrice, time_placed", "SellOrder"]);
- select.push(["id, quantity, maxPrice, time_placed", "BuyOrder"]);
- let promises = select.map(a => DB.query("SELECT " + a[0] + " FROM " + a[1] + " WHERE floID=?", [floID]));
+ select.push(["balance", "Cash"]);
+ select.push(["asset, AVG(base) AS avg_base, SUM(quantity) AS quantity", "Vault", "GROUP BY asset"]);
+ select.push(["id, asset, quantity, minPrice, time_placed", "SellOrder"]);
+ select.push(["id, asset, quantity, maxPrice, time_placed", "BuyOrder"]);
+ let promises = select.map(a => DB.query(`SELECT ${a[0]} FROM ${a[1]} WHERE floID=? ${a[2] || ""}`, [floID]));
Promise.allSettled(promises).then(results => {
let response = {
floID: floID,
@@ -117,10 +150,10 @@ function getAccountDetails(floID) {
else
switch (i) {
case 0:
- response.rupee_total = a.value[0].rupeeBalance;
+ response.cash = a.value[0].balance;
break;
case 1:
- response.coins = a.value;
+ response.vault = a.value;
break;
case 2:
response.sellOrders = a.value;
@@ -130,7 +163,7 @@ function getAccountDetails(floID) {
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)
.catch(error => console.error(error))
.finally(_ => resolve(response));
@@ -140,7 +173,7 @@ function getAccountDetails(floID) {
function depositFLO(floID, txid) {
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) {
switch (result[0].status) {
case "PENDING":
@@ -151,7 +184,7 @@ function depositFLO(floID, txid) {
return reject(INVALID("Transaction already used to add coins"));
}
} 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"))
.catch(error => reject(error));
}).catch(error => reject(error))
@@ -159,19 +192,19 @@ function depositFLO(floID, txid) {
}
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 => {
confirmDepositFLO.checkTx(req.floID, req.txid).then(amount => {
let txQueries = [];
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)
- .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);
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));
});
})
@@ -206,45 +239,23 @@ function withdrawFLO(floID, amount) {
return reject(INVALID("Invalid FLO ID"));
else if (typeof amount !== "number" || amount <= 0)
return reject(INVALID(`Invalid amount (${amount})`));
- DB.query("SELECT SUM(quantity) AS total FROM Vault WHERE floID=?", [floID]).then(result => {
- let total = result.pop()["total"] || 0;
- if (total < amount)
- return reject(INVALID("Insufficient FLO"));
- DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=?", [floID]).then(result => {
- let locked = result.pop()["locked"] || 0;
- let available = total - locked;
- if (available < amount)
- return reject(INVALID("Insufficient FLO (Some FLO are locked in sell orders)"));
- DB.query("SELECT id, quantity, base FROM Vault WHERE floID=? ORDER BY locktime", [floID]).then(coins => {
- let rem = amount,
- 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 -= 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));
+ getAssetBalance.check(floID, "FLO", amount).then(_ => {
+ consumeAsset(floID, "FLO", amount).then(txQueries => {
+ 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));
@@ -252,13 +263,13 @@ function withdrawFLO(floID, amount) {
}
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 => {
floBlockchainAPI.sendTx(global.myFloID, req.floID, req.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("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));
}).catch(error => console.error(error));
})
@@ -266,22 +277,22 @@ function retryWithdrawalFLO() {
}
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 => {
floBlockchainAPI.getTx(req.txid).then(tx => {
if (!tx.blockheight || !tx.confirmations) //Still not confirmed
return;
- DB.query("UPDATE outputFLO SET status=? WHERE id=?", ["SUCCESS", req.id])
- .then(result => console.debug("FLO withdrawed for ", req.floID))
+ DB.query("UPDATE OutputFLO SET status=? WHERE id=?", ["SUCCESS", req.id])
+ .then(result => console.debug("FLO withdrawed:", req.floID, req.amount))
.catch(error => console.error(error))
}).catch(error => console.error(error));
})
}).catch(error => console.error(error));
}
-function depositRupee(floID, txid) {
+function depositToken(floID, txid) {
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) {
switch (result[0].status) {
case "PENDING":
@@ -292,53 +303,58 @@ function depositRupee(floID, txid) {
return reject(INVALID("Transaction already used to add tokens"));
}
} 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"))
.catch(error => reject(error));
}).catch(error => reject(error))
});
}
-function confirmDepositRupee() {
- DB.query("SELECT id, floID, txid FROM inputRupee WHERE status=?", ["PENDING"]).then(results => {
+function confirmDepositToken() {
+ DB.query("SELECT id, floID, txid FROM InputToken WHERE status=?", ["PENDING"]).then(results => {
results.forEach(req => {
- confirmDepositRupee.checkTx(req.floID, req.txid).then(amounts => {
- DB.query("SELECT id FROM inputFLO where floID=? AND txid=?", [req.floID, req.txid]).then(result => {
+ confirmDepositToken.checkTx(req.floID, req.txid).then(amounts => {
+ DB.query("SELECT id FROM InputFLO where floID=? AND txid=?", [req.floID, req.txid]).then(result => {
let txQueries = [],
- amount_rupee = amounts[0];
+ token_name = amounts[0],
+ amount_token = amounts[1];
//Add the FLO balance if necessary
if (!result.length) {
- let amount_flo = amounts[1];
- txQueries.push(["INSERT INTO Vault(floID, quantity) VALUES (?, ?)", [req.floID, amount_flo]]);
- txQueries.push(["INSERT INTO inputFLO(txid, floID, amount, status) VALUES (?, ?, ?, ?)", [req.txid, req.floID, amount_flo, "SUCCESS"]]);
+ let amount_flo = amounts[2];
+ 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(["UPDATE inputRupee SET status=? WHERE id=?", ["SUCCESS", req.id]]);
- txQueries.push(["UPDATE Cash SET rupeeBalance=rupeeBalance+? WHERE floID=?", [amount_rupee, req.floID]]);
+ txQueries.push(["UPDATE InputToken SET status=?, token=?, amount=? WHERE id=?", ["SUCCESS", token_name, amount_token, req.id]]);
+ 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)
- .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);
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));
});
})
}).catch(error => console.error(error))
}
-confirmDepositRupee.checkTx = function(sender, txid) {
+confirmDepositToken.checkTx = function(sender, txid) {
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 => {
if (tx.parsedFloData.type !== "transfer")
return reject([true, "Transaction type not 'transfer'"]);
else if (tx.parsedFloData.transferType !== "token")
return reject([true, "Transaction transfer is not 'token'"]);
- else if (tx.parsedFloData.tokenIdentification !== "rupee")
- return reject([true, "Transaction token is not 'rupee'"]);
- var amount_rupee = tx.parsedFloData.tokenAmount;
+ var token_name = tx.parsedFloData.tokenIdentification,
+ amount_token = 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)
if (!vin_sender.length)
return reject([true, "Transaction not sent by the sender"]);
@@ -346,60 +362,36 @@ confirmDepositRupee.checkTx = function(sender, txid) {
if (amount_flo == 0)
return reject([true, "Transaction receiver is not market ID"]);
else
- resolve([amount_rupee, amount_flo]);
+ resolve([token_name, amount_token, amount_flo]);
}).catch(error => reject([false, error]))
})
}
-function withdrawRupee(floID, amount) {
+function withdrawToken(floID, token, amount) {
return new Promise((resolve, reject) => {
if (!floID || !floCrypto.validateAddr(floID))
return reject(INVALID("Invalid FLO ID"));
else if (typeof amount !== "number" || amount <= 0)
return reject(INVALID(`Invalid amount (${amount})`));
- DB.query("SELECT SUM(quantity) AS total FROM Vault WHERE floID=?", [floID]).then(result => {
- let required_flo = floGlobals.sendAmt + floGlobals.fee,
- total = result.pop()["total"] || 0;
- if (total < required_flo)
- return reject(INVALID(`Insufficient FLO! Required ${required_flo} FLO to withdraw tokens`));
- DB.query("SELECT SUM(quantity) AS locked FROM SellOrder WHERE floID=?", [floID]).then(result => {
- let locked = result.pop()["locked"] || 0;
- let available = total - locked;
- 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]]);
-
+ else if (!assetList.includes(token) || token === "FLO")
+ return reject(INVALID("Invalid Token"));
+ //Check for FLO balance (transaction fee)
+ const required_flo = floGlobals.sendAmt + floGlobals.fee;
+ getAssetBalance.check(floID, "FLO", required_flo).then(_ => {
+ getAssetBalance.check(floID, token, amount).then(_ => {
+ consumeAsset(floID, "FLO", required_flo).then(txQueries => {
+ consumeAsset(floID, token, amount, txQueries).then(txQueries => {
DB.transaction(txQueries).then(result => {
//Send FLO to user via blockchain API
- tokenAPI.sendToken(global.myPrivKey, amount, '(withdrawal from market)', floID).then(txid => {
- if (!txid)
- throw Error("Transaction not successful");
+ tokenAPI.sendToken(global.myPrivKey, amount, floID, '(withdrawal from market)', token).then(txid => {
+ if (!txid) throw Error("Transaction not successful");
//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))
.finally(_ => resolve("Withdrawal was successful"));
}).catch(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))
.finally(_ => resolve("Withdrawal request is in process"));
});
@@ -411,26 +403,26 @@ function withdrawRupee(floID, amount) {
});
}
-function retryWithdrawalRupee() {
- DB.query("SELECT id, floID, amount FROM outputRupee WHERE status=?", ["PENDING"]).then(results => {
+function retryWithdrawalToken() {
+ DB.query("SELECT id, floID, token, amount FROM OutputToken WHERE status=?", ["PENDING"]).then(results => {
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)
throw Error("Transaction not successful");
//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));
}).catch(error => console.error(error));
});
}).catch(error => reject(error));
}
-function confirmWithdrawalRupee() {
- DB.query("SELECT id, floID, amount, txid FROM outputRupee WHERE status=?", ["WAITING_CONFIRMATION"]).then(results => {
+function confirmWithdrawalToken() {
+ DB.query("SELECT id, floID, token, amount, txid FROM OutputToken WHERE status=?", ["WAITING_CONFIRMATION"]).then(results => {
results.forEach(req => {
tokenAPI.getTx(req.txid).then(tx => {
- DB.query("UPDATE outputRupee SET status=? WHERE id=?", ["SUCCESS", req.id])
- .then(result => console.debug("Rupee withdrawed for ", req.floID))
+ DB.query("UPDATE OutputToken SET status=? WHERE id=?", ["SUCCESS", req.id])
+ .then(result => console.debug("Token withdrawed:", req.floID, req.token, req.amount))
.catch(error => console.error(error));
}).catch(error => console.error(error));
})
@@ -439,21 +431,21 @@ function confirmWithdrawalRupee() {
function periodicProcess() {
blockchainReCheck();
- coupling.initiate();
+ assetList.forEach(asset => coupling.initiate(asset));
}
function blockchainReCheck() {
confirmDepositFLO();
- confirmDepositRupee();
+ confirmDepositToken();
retryWithdrawalFLO();
- retryWithdrawalRupee();
+ retryWithdrawalToken();
confirmWithdrawalFLO();
- confirmWithdrawalRupee();
+ confirmWithdrawalToken();
}
module.exports = {
- get rate() {
- return coupling.price.currentRate;
+ get rates() {
+ return coupling.price.currentRates;
},
addBuyOrder,
addSellOrder,
@@ -461,12 +453,15 @@ module.exports = {
getAccountDetails,
depositFLO,
withdrawFLO,
- depositRupee,
- withdrawRupee,
+ depositToken,
+ withdrawToken,
periodicProcess,
group: coupling.group,
set DB(db) {
DB = db;
coupling.DB = db;
+ },
+ set assetList(assets) {
+ assetList = assets;
}
};
\ No newline at end of file
diff --git a/src/price.js b/src/price.js
index eb833ee..c738075 100644
--- a/src/price.js
+++ b/src/price.js
@@ -10,41 +10,48 @@ const MIN_TIME = 10 * 1000, // 1 * 60 * 60 * 1000,
var DB; //container for database
-var cur_rate, //container for FLO price (from API or by model)
- lastTime = Date.now(), //container for timestamp of the last tx
- noBuyOrder,
- noSellOrder;
+var currentRate = {}, //container for FLO price (from API or by model)
+ lastTime = {}, //container for timestamp of the last tx
+ noBuyOrder = {},
+ noSellOrder = {};
-const updateLastTime = () => lastTime = Date.now();
+const updateLastTime = asset => lastTime[asset] = Date.now();
//store FLO price in DB every 1 hr
-function storeRate(rate = cur_rate) {
- DB.query("INSERT INTO priceHistory (rate) VALUE (?)", rate)
+function storeRate(asset, rate) {
+ DB.query("INSERT INTO PriceHistory (asset, rate) VALUE (?, ?)", [asset, rate])
.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) => {
- 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'))
.catch(error => reject(error))
});
}
-function loadRate() {
+function loadRate(asset) {
return new Promise((resolve, reject) => {
- if (typeof cur_rate !== "undefined")
- return resolve(cur_rate);
- DB.query("SELECT rate FROM priceHistory ORDER BY rec_time DESC LIMIT 1").then(result => {
+ if (typeof currentRate[asset] !== "undefined")
+ return resolve(currentRate[asset]);
+ updateLastTime(asset);
+ DB.query("SELECT rate FROM PriceHistory WHERE asset=? ORDER BY rec_time DESC LIMIT 1", [asset]).then(result => {
if (result.length)
- resolve(cur_rate = result[0].rate);
+ resolve(currentRate[asset] = result[0].rate);
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));
})
}
+/*
function fetchRates() {
return new Promise((resolve, reject) => {
fetchRates.FLO_USD().then(FLO_rate => {
@@ -83,57 +90,58 @@ fetchRates.USD_INR = function() {
}).catch(error => reject(error));
});
}
+*/
-function getRates() {
+function getRates(asset) {
return new Promise((resolve, reject) => {
- loadRate().then(_ => {
- console.debug(cur_rate);
+ loadRate(asset).then(_ => {
+ console.debug(asset, currentRate[asset]);
let cur_time = Date.now();
- if (cur_time - lastTime < MIN_TIME) //Minimum time to update not crossed: No update required
- resolve(cur_rate);
- else if (noBuyOrder && noSellOrder) //Both are not available: No update required
- resolve(cur_rate);
- else if (noBuyOrder === null || noSellOrder === null) //An error has occured during last process: No update (might cause price to crash/jump)
- resolve(cur_rate);
+ if (cur_time - lastTime[asset] < MIN_TIME) //Minimum time to update not crossed: No update required
+ resolve(currentRate[asset]);
+ else if (noBuyOrder[asset] && noSellOrder[asset]) //Both are not available: No update required
+ resolve(currentRate[asset]);
+ else if (noBuyOrder[asset] === null || noSellOrder[asset] === null) //An error has occured during last process: No update (might cause price to crash/jump)
+ resolve(currentRate[asset]);
else
- getPastRate().then(ratePast24hr => {
- if (noBuyOrder) {
+ getPastRate(asset).then(ratePast24hr => {
+ if (noBuyOrder[asset]) {
//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)) {
- cur_rate = tmp_val;
- updateLastTime();
+ currentRate[asset] = tmp_val;
+ updateLastTime(asset);
} else
console.debug("Max Price down for the day has reached");
- resolve(cur_rate);
- } else if (noSellOrder) {
+ resolve(currentRate[asset]);
+ } else if (noSellOrder[asset]) {
//No Sell, But Buy available: Increase the price
checkForRatedSellers().then(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)) {
- cur_rate = tmp_val;
- updateLastTime();
+ currentRate[asset] = tmp_val;
+ updateLastTime(asset);
} else
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 => {
console.error(error);
- resolve(cur_rate);
+ resolve(currentRate[asset]);
});
}).catch(error => reject(error));
})
}
-function checkForRatedSellers() {
+function checkForRatedSellers(asset) {
//Check if there are best rated sellers?
return new Promise((resolve, reject) => {
DB.query("SELECT MAX(sellPriority) as max_p FROM TagList").then(result => {
let ratedMin = result[0].max_p * (1 - TOP_RANGE);
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 => {
resolve(result[0].value > 0);
}).catch(error => reject(error))
@@ -144,14 +152,14 @@ function checkForRatedSellers() {
module.exports = {
getRates,
updateLastTime,
- noOrder(buy, sell) {
- noBuyOrder = buy;
- noSellOrder = sell;
+ noOrder(asset, buy, sell) {
+ noBuyOrder[asset] = buy;
+ noSellOrder[asset] = sell;
},
set DB(db) {
DB = db;
},
- get currentRate() {
- return cur_rate
+ get currentRates() {
+ return Object.assign({}, currentRate);
}
}
\ No newline at end of file
diff --git a/src/request.js b/src/request.js
index 8f4055e..dc04956 100644
--- a/src/request.js
+++ b/src/request.js
@@ -22,19 +22,19 @@ const oneDay = 1000 * 60 * 60 * 24;
const maxSessionTimeout = 60 * oneDay;
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) {
return new Promise((resolve, reject) => {
if (!serving)
return reject(INVALID(INVALID_SERVER_MSG));
else if (!floCrypto.validateAddr(floID))
- return reject(INVALID.e_code).send("Invalid floID");
- DB.query("SELECT " + (proxy ? "session_time, proxyKey AS pubKey FROM Sessions" : "pubKey FROM Users") + " WHERE floID=?", [floID]).then(result => {
+ return reject(INVALID("Invalid floID"));
+ DB.query("SELECT " + (proxy ? "session_time, proxyKey AS pubKey FROM UserSession" : "pubKey FROM Users") + " WHERE floID=?", [floID]).then(result => {
if (result.length < 1)
return reject(INVALID(proxy ? "Session not active" : "User not registered"));
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);
req_str instanceof INVALID ? reject(req_str) : resolve(req_str);
}).catch(error => reject(error));
@@ -62,6 +62,8 @@ function storeRequest(floID, req_str, sign) {
}
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 hash = Crypto.SHA1(randID + secret);
res.send({
@@ -111,7 +113,7 @@ function Login(req, res) {
proxyKey: data.proxyKey,
timestamp: data.timestamp
}, 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",
[data.floID, data.proxyKey]).then(_ => {
storeRequest(data.floID, req_str, data.sign);
@@ -136,7 +138,7 @@ function Logout(req, res) {
type: "logout",
timestamp: data.timestamp
}, 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);
res.send('Logout successful');
}).catch(error => {
@@ -157,11 +159,12 @@ function PlaceSellOrder(req, res) {
let data = req.body;
validateRequestFromFloID({
type: "sell_order",
+ asset: data.asset,
quantity: data.quantity,
min_price: data.min_price,
timestamp: data.timestamp
}, 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 => {
storeRequest(data.floID, req_str, data.sign);
res.send('Sell Order placed successfully');
@@ -187,11 +190,12 @@ function PlaceBuyOrder(req, res) {
let data = req.body;
validateRequestFromFloID({
type: "buy_order",
+ asset: data.asset,
quantity: data.quantity,
max_price: data.max_price,
timestamp: data.timestamp
}, 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 => {
storeRequest(data.floID, req_str, data.sign);
res.send('Buy Order placed successfully');
@@ -259,16 +263,16 @@ function ListBuyOrders(req, res) {
function ListTransactions(req, res) {
//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))
.catch(error => res.status(INTERNAL.e_code).send("Try again later!"));
}
-function getRate(req, res) {
+function getRates(req, res) {
if (!serving)
res.status(INVALID.e_code).send(INVALID_SERVER_MSG);
else
- res.send(`${market.rate}`);
+ res.send(market.rates);
}
function Account(req, res) {
@@ -349,14 +353,14 @@ function WithdrawFLO(req, res) {
});
}
-function DepositRupee(req, res) {
+function DepositToken(req, res) {
let data = req.body;
validateRequestFromFloID({
- type: "deposit_Rupee",
+ type: "deposit_Token",
txid: data.txid,
timestamp: data.timestamp
}, 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);
res.send(result);
}).catch(error => {
@@ -377,14 +381,15 @@ function DepositRupee(req, res) {
});
}
-function WithdrawRupee(req, res) {
+function WithdrawToken(req, res) {
let data = req.body;
validateRequestFromFloID({
- type: "withdraw_Rupee",
+ type: "withdraw_Token",
+ token: data.token,
amount: data.amount,
timestamp: data.timestamp
}, 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);
res.send(result);
}).catch(error => {
@@ -479,18 +484,21 @@ module.exports = {
ListSellOrders,
ListBuyOrders,
ListTransactions,
- getRate,
+ getRates,
Account,
DepositFLO,
WithdrawFLO,
- DepositRupee,
- WithdrawRupee,
+ DepositToken,
+ WithdrawToken,
periodicProcess: market.periodicProcess,
addUserTag,
removeUserTag,
set trustedIDs(ids) {
trustedIDs = ids;
},
+ set assetList(assets){
+ market.assetList = assets;
+ },
set DB(db) {
DB = db;
market.DB = db;
diff --git a/src/set_globals.js b/src/set_globals.js
index b743c93..f402c37 100644
--- a/src/set_globals.js
+++ b/src/set_globals.js
@@ -11,4 +11,13 @@ try {
} finally {
for (let p in param)
global[p] = param[p];
-}
\ No newline at end of file
+}
+
+/*
+//Trace the debug logs in node js
+var debug = console.debug;
+console.debug = function() {
+ debug.apply(console, arguments);
+ console.trace();
+};
+*/
\ No newline at end of file
diff --git a/src/tokenAPI.js b/src/tokenAPI.js
index be96954..4a3ccb0 100644
--- a/src/tokenAPI.js
+++ b/src/tokenAPI.js
@@ -14,7 +14,7 @@
}).catch(error => reject(error))
})
},
- getBalance: function(floID, token = floGlobals.token) {
+ getBalance: function(floID, token = floGlobals.currency) {
return new Promise((resolve, reject) => {
this.fetch_api(`api/v1.0/getFloAddressBalance?token=${token}&floAddress=${floID}`)
.then(result => resolve(result.balance || 0))
@@ -35,7 +35,7 @@
}).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) => {
let senderID = floCrypto.getFloID(privKey);
if (typeof amount !== "number" || amount <= 0)