diff --git a/args/schema.sql b/args/schema.sql index 0d3ac69..e1ab126 100644 --- a/args/schema.sql +++ b/args/schema.sql @@ -171,7 +171,21 @@ CREATE TABLE PriceHistory ( FOREIGN KEY (asset) REFERENCES AssetList(asset) ); -CREATE TABLE TransactionHistory ( +CREATE TABLE TransferTransactions ( + id INT NOT NULL AUTO_INCREMENT, + sender CHAR(34) NOT NULL, + receiver CHAR(34) NOT NULL, + token VARCHAR(64) NOT NULL, + amount FLOAT NOT NULL, + tx_time DATETIME DEFAULT CURRENT_TIMESTAMP, + txid VARCHAR(66) NOT NULL, + KEY(id), + PRIMARY KEY(txid), + FOREIGN KEY (sender) REFERENCES Users(floID), + FOREIGN KEY (receiver) REFERENCES Users(floID) +); + +CREATE TABLE TradeTransactions ( id INT NOT NULL AUTO_INCREMENT, seller CHAR(34) NOT NULL, buyer CHAR(34) NOT NULL, @@ -179,13 +193,15 @@ CREATE TABLE TransactionHistory ( quantity FLOAT NOT NULL, unitValue DECIMAL(10, 2) NOT NULL, tx_time DATETIME DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY(id), + txid VARCHAR(66) NOT NULL, + KEY(id), + PRIMARY KEY(txid), FOREIGN KEY (buyer) REFERENCES Users(floID), FOREIGN KEY (seller) REFERENCES Users(floID), FOREIGN KEY (asset) REFERENCES AssetList(asset) ); -CREATE TABLE AuditTransaction( +CREATE TABLE AuditTrade( id INT NOT NULL AUTO_INCREMENT, rec_time DATETIME DEFAULT CURRENT_TIMESTAMP, unit_price FLOAT NOT NULL, @@ -324,16 +340,23 @@ FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('PriceHistory', NEW.id) ON CREATE TRIGGER PriceHistory_D AFTER DELETE ON PriceHistory FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('PriceHistory', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; -CREATE TRIGGER AuditTransaction_I AFTER INSERT ON AuditTransaction -FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('AuditTransaction', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; -CREATE TRIGGER AuditTransaction_U AFTER UPDATE ON AuditTransaction -FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('AuditTransaction', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; -CREATE TRIGGER AuditTransaction_D AFTER DELETE ON AuditTransaction -FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('AuditTransaction', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; +CREATE TRIGGER AuditTransaction_I AFTER INSERT ON AuditTrade +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('AuditTrade', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; +CREATE TRIGGER AuditTransaction_U AFTER UPDATE ON AuditTrade +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('AuditTrade', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; +CREATE TRIGGER AuditTransaction_D AFTER DELETE ON AuditTrade +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('AuditTrade', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; -CREATE TRIGGER TransactionHistory_I AFTER INSERT ON TransactionHistory -FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TransactionHistory', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; -CREATE TRIGGER TransactionHistory_U AFTER UPDATE ON TransactionHistory -FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TransactionHistory', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; -CREATE TRIGGER TransactionHistory_D AFTER DELETE ON TransactionHistory -FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TransactionHistory', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; +CREATE TRIGGER TransactionHistory_I AFTER INSERT ON TradeTransactions +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TradeTransactions', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; +CREATE TRIGGER TransactionHistory_U AFTER UPDATE ON TradeTransactions +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TradeTransactions', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; +CREATE TRIGGER TransactionHistory_D AFTER DELETE ON TradeTransactions +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TradeTransactions', OLD.id) ON DUPLICATE KEY UPDATE mode=NULL, timestamp=DEFAULT; + +CREATE TRIGGER TransferTransactions_I AFTER INSERT ON TransferTransactions +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TransferTransactions', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; +CREATE TRIGGER TransferTransactions_U AFTER UPDATE ON TransferTransactions +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TransferTransactions', NEW.id) ON DUPLICATE KEY UPDATE mode=TRUE, timestamp=DEFAULT; +CREATE TRIGGER TransferTransactions_D AFTER DELETE ON TransferTransactions +FOR EACH ROW INSERT INTO _backup (t_name, id) VALUES ('TransferTransactions', 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 fea8f49..4ded68d 100644 --- a/args/truncateAll.sql +++ b/args/truncateAll.sql @@ -1,6 +1,6 @@ /* Node data */ TRUNCATE _backup; -TRUNCATE AuditTransaction; +TRUNCATE AuditTrade; TRUNCATE BuyOrder; TRUNCATE Cash; TRUNCATE InputFLO; @@ -12,7 +12,8 @@ TRUNCATE RequestLog; TRUNCATE SellOrder; TRUNCATE UserSession; TRUNCATE UserTag; -TRUNCATE TransactionHistory; +TRUNCATE TransferTransactions; +TRUNCATE TradeTransactions; TRUNCATE Vault; DELETE FROM Users; diff --git a/public/api.js b/public/api.js index 1c3e36b..9688cd0 100644 --- a/public/api.js +++ b/public/api.js @@ -371,6 +371,41 @@ function cancelOrder(type, id, floID, proxySecret) { }) } +function transferToken(receiver, token, amount, floID, proxySecret) { + return new Promise((resolve, reject) => { + if (!floCrypto.validateAddr(receiver)) + return reject(INVALID(`Invalid receiver (${receiver})`)); + else if (typeof amount !== "number" || amount <= 0) + return reject(`Invalid amount (${amount})`); + let request = { + floID: floID, + token: token, + receiver: receiver, + amount: amount, + timestamp: Date.now() + }; + request.sign = signRequest({ + type: "transfer_token", + receiver: receiver, + token: token, + amount: amount, + timestamp: request.timestamp + }, proxySecret); + console.debug(request); + + exchangeAPI('/transfer-token', { + method: "POST", + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(request) + }).then(result => responseParse(result, false) + .then(result => resolve(result)) + .catch(error => reject(error))) + .catch(error => reject(error)) + }) +} + function depositFLO(quantity, floID, sinkID, privKey, proxySecret) { return new Promise((resolve, reject) => { if (typeof quantity !== "number" || quantity <= floGlobals.fee) @@ -382,7 +417,7 @@ function depositFLO(quantity, floID, sinkID, privKey, proxySecret) { timestamp: Date.now() }; request.sign = signRequest({ - type: "deposit_FLO", + type: "deposit_flo", txid: txid, timestamp: request.timestamp }, proxySecret); @@ -410,7 +445,7 @@ function withdrawFLO(quantity, floID, proxySecret) { timestamp: Date.now() }; request.sign = signRequest({ - type: "withdraw_FLO", + type: "withdraw_flo", amount: quantity, timestamp: request.timestamp }, proxySecret); @@ -440,7 +475,7 @@ function depositToken(token, quantity, floID, sinkID, privKey, proxySecret) { timestamp: Date.now() }; request.sign = signRequest({ - type: "deposit_Token", + type: "deposit_token", txid: txid, timestamp: request.timestamp }, proxySecret); @@ -469,7 +504,7 @@ function withdrawToken(token, quantity, floID, proxySecret) { timestamp: Date.now() }; request.sign = signRequest({ - type: "withdraw_Token", + type: "withdraw_token", token: token, amount: quantity, timestamp: request.timestamp @@ -498,7 +533,7 @@ function addUserTag(tag_user, tag, floID, proxySecret) { timestamp: Date.now() }; request.sign = signRequest({ - command: "add_Tag", + type: "add_tag", user: tag_user, tag: tag, timestamp: request.timestamp @@ -527,7 +562,7 @@ function removeUserTag(tag_user, tag, floID, proxySecret) { timestamp: Date.now() }; request.sign = signRequest({ - command: "remove_Tag", + type: "remove_tag", user: tag_user, tag: tag, timestamp: request.timestamp diff --git a/src/_constants.js b/src/_constants.js index 47f78ae..ea9eb8c 100644 --- a/src/_constants.js +++ b/src/_constants.js @@ -8,7 +8,9 @@ module.exports = { INVALID_SERVER_MSG: "INCORRECT_SERVER_ERROR" //Should be reflected in public backend script }, market: { - MINIMUM_BUY_REQUIREMENT: 0 + MINIMUM_BUY_REQUIREMENT: 0, + TRADE_HASH_PREFIX: "z1", + TRANSFER_HASH_PREFIX: "z0" }, price: { MIN_TIME: 1 * 60 * 60 * 1000, // 1 hr diff --git a/src/app.js b/src/app.js index 3f2fa66..aaa663b 100644 --- a/src/app.js +++ b/src/app.js @@ -68,6 +68,9 @@ module.exports = function App(secret, DB) { //cancel sell or buy order app.post('/cancel', Request.CancelOrder); + //transfer amount to another user + app.post('/transfer-token', Request.TransferToken); + //list sell or buy order app.get('/list-sellorders', Request.ListSellOrders); app.get('/list-buyorders', Request.ListBuyOrders); @@ -86,7 +89,6 @@ module.exports = function App(secret, DB) { app.post('/withdraw-token', Request.WithdrawToken); //Manage user tags (Access to trusted IDs only) - app.post('/add-tag', Request.addUserTag); app.post('/remove-tag', Request.removeUserTag); diff --git a/src/coupling.js b/src/coupling.js index d09f4d9..152e517 100644 --- a/src/coupling.js +++ b/src/coupling.js @@ -3,10 +3,15 @@ const group = require("./group"); const price = require("./price"); +const { + TRADE_HASH_PREFIX +} = require("./_constants")["market"]; + var DB; //container for database function startCouplingForAsset(asset) { price.getRates(asset).then(cur_rate => { + cur_rate = cur_rate.toFixed(3); group.getBestPairs(asset, cur_rate) .then(bestPairQueue => processCoupling(bestPairQueue)) .catch(error => console.error("initiateCoupling", error)) @@ -112,7 +117,12 @@ function updateBalance(seller_best, buyer_best, txQueries, asset, cur_price, qua //Add coins to Buyer txQueries.push(["INSERT INTO Vault(floID, asset, base, quantity) VALUES (?, ?, ?, ?)", [buyer_best.floID, asset, cur_price, quantity]]) //Record transaction - txQueries.push(["INSERT INTO TransactionHistory (seller, buyer, asset, quantity, unitValue) VALUES (?, ?, ?, ?, ?)", [seller_best.floID, buyer_best.floID, asset, quantity, cur_price]]); + let time = Date.now(); + let hash = TRADE_HASH_PREFIX + Crypto.SHA256([time, seller_best.floID, buyer_best.floID, asset, quantity, cur_price].join("|")); + txQueries.push([ + "INSERT INTO TradeTransactions (seller, buyer, asset, quantity, unitValue, tx_time, txid) VALUES (?, ?, ?, ?, ?, ?, ?)", + [seller_best.floID, buyer_best.floID, asset, quantity, cur_price, global.convertDateToString(time), hash] + ]); } function beginAudit(sellerID, buyerID, asset, unit_price, quantity) { @@ -125,7 +135,7 @@ function beginAudit(sellerID, buyerID, asset, unit_price, quantity) { 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," + + DB.query("INSERT INTO AuditTrade (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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [ diff --git a/src/database.js b/src/database.js index 951e2c4..298aeaa 100644 --- a/src/database.js +++ b/src/database.js @@ -86,6 +86,7 @@ function Database(user, password, dbname, host = 'localhost') { user: user, password: password, database: dbname, + //dateStrings : true, timezone: 'UTC' }); db.connect.then(conn => { diff --git a/src/market.js b/src/market.js index c3725f9..32b4f15 100644 --- a/src/market.js +++ b/src/market.js @@ -3,11 +3,21 @@ const coupling = require('./coupling'); const { - MINIMUM_BUY_REQUIREMENT + MINIMUM_BUY_REQUIREMENT, + TRANSFER_HASH_PREFIX } = require('./_constants')["market"]; var DB, assetList; //container for database and allowed assets +const checkIfUserRegistered = floID => new Promise((resolve, reject) => { + DB.query("SELECT id FROM Users WHERE floID=?", [floID]).then(result => { + if (result.length) + resolve(result[0].id); + else + reject(INVALID(`User ${floID} not registered`)); + }).catch(error => reject(error)); +}); + const getAssetBalance = (floID, asset) => new Promise((resolve, reject) => { let promises = (asset === floGlobals.currency) ? [ DB.query("SELECT balance FROM Cash WHERE floID=?", [floID]), @@ -32,7 +42,7 @@ getAssetBalance.check = (floID, asset, amount) => new Promise((resolve, reject) 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 @@ -60,8 +70,8 @@ const consumeAsset = (floID, asset, amount, txQueries = []) => new Promise((reso function addSellOrder(floID, asset, quantity, min_price) { return new Promise((resolve, reject) => { - if (!floID || !floCrypto.validateAddr(floID)) - return reject(INVALID("Invalid FLO ID")); + if (!floCrypto.validateAddr(floID)) + return reject(INVALID(`Invalid floID (${floID})`)); else if (typeof quantity !== "number" || quantity <= 0) return reject(INVALID(`Invalid quantity (${quantity})`)); else if (typeof min_price !== "number" || min_price <= 0) @@ -71,7 +81,7 @@ function addSellOrder(floID, asset, quantity, min_price) { getAssetBalance.check(floID, asset, quantity).then(_ => { checkSellRequirement(floID, asset).then(_ => { DB.query("INSERT INTO SellOrder(floID, asset, quantity, minPrice) VALUES (?, ?, ?, ?)", [floID, asset, quantity, min_price]) - .then(result => resolve("Added SellOrder to DB")) + .then(result => resolve('Sell Order placed successfully')) .catch(error => reject(error)); }).catch(error => reject(error)) }).catch(error => reject(error)); @@ -83,7 +93,7 @@ const checkSellRequirement = (floID, asset) => new Promise((resolve, reject) => 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=? AND asset=?", [floID, asset]).then(result => { + DB.query("SELECT SUM(quantity) AS brought FROM TradeTransactions WHERE buyer=? AND asset=?", [floID, asset]).then(result => { if (result[0].brought >= MINIMUM_BUY_REQUIREMENT) resolve(true); else @@ -94,8 +104,8 @@ const checkSellRequirement = (floID, asset) => new Promise((resolve, reject) => function addBuyOrder(floID, asset, quantity, max_price) { return new Promise((resolve, reject) => { - if (!floID || !floCrypto.validateAddr(floID)) - return reject(INVALID("Invalid FLO ID")); + if (!floCrypto.validateAddr(floID)) + return reject(INVALID(`Invalid floID (${floID})`)); else if (typeof quantity !== "number" || quantity <= 0) return reject(INVALID(`Invalid quantity (${quantity})`)); else if (typeof max_price !== "number" || max_price <= 0) @@ -104,7 +114,7 @@ function addBuyOrder(floID, asset, quantity, max_price) { return reject(INVALID(`Invalid asset (${asset})`)); getAssetBalance.check(floID, floGlobals.currency, quantity * max_price).then(_ => { DB.query("INSERT INTO BuyOrder(floID, asset, quantity, maxPrice) VALUES (?, ?, ?, ?)", [floID, asset, quantity, max_price]) - .then(result => resolve("Added BuyOrder to DB")) + .then(result => resolve('Buy Order placed successfully')) .catch(error => reject(error)); }).catch(error => reject(error)); }); @@ -112,8 +122,8 @@ function addBuyOrder(floID, asset, quantity, max_price) { function cancelOrder(type, id, floID) { return new Promise((resolve, reject) => { - if (!floID || !floCrypto.validateAddr(floID)) - return reject(INVALID("Invalid FLO ID")); + if (!floCrypto.validateAddr(floID)) + return reject(INVALID(`Invalid floID (${floID})`)); let tableName; if (type === "buy") tableName = "BuyOrder"; @@ -166,7 +176,7 @@ function getAccountDetails(floID) { break; } }); - DB.query("SELECT * FROM TransactionHistory WHERE seller=? OR buyer=?", [floID, floID]) + DB.query("SELECT * FROM TradeTransactions WHERE seller=? OR buyer=?", [floID, floID]) .then(result => response.transactions = result) .catch(error => console.error(error)) .finally(_ => resolve(response)); @@ -174,6 +184,38 @@ function getAccountDetails(floID) { }); } +function transferToken(sender, receiver, token, amount) { + return new Promise((resolve, reject) => { + if (floCrypto.validateAddr(sender)) + return reject(INVALID(`Invalid sender (${sender})`)); + else if (floCrypto.validateAddr(receiver)) + return reject(INVALID(`Invalid receiver (${receiver})`)); + else if (typeof amount !== "number" || amount <= 0) + return reject(INVALID(`Invalid amount (${amount})`)); + else if (token !== floGlobals.currency && !assetList.includes(token)) + return reject(INVALID(`Invalid token (${token})`)); + getAssetBalance.check(senderID, token, amount).then(_ => { + checkIfUserRegistered(receiver).then(_ => { + consumeAsset(sender, token, amount).then(txQueries => { + if (token === floGlobals.currency) + txQueries.push(["UPDATE Cash SET balance=balance+? WHERE floID=?", [amount, receiver]]); + else + txQueries.push(["INSERT INTO Vault(floID, quantity) VALUES (?, ?)", [receiver, amount]]); + let time = Date.now(); + let hash = TRANSFER_HASH_PREFIX + Crypto.SHA256([time, sender, receiver, token, amount].join("|")); + txQueries.push([ + "INSERT INTO TransferTransactions (sender, receiver, token, amount, tx_time, txid)", + [sender, receiver, token, amount, global.convertDateToString(time), hash] + ]); + DB.transaction(txQueries) + .then(result => resolve(hash)) + .catch(error => reject(error)) + }).catch(error => reject(error)) + }).catch(error => reject(error)) + }).catch(error => reject(error)) + }) +} + function depositFLO(floID, txid) { return new Promise((resolve, reject) => { DB.query("SELECT status FROM InputFLO WHERE txid=? AND floID=?", [txid, floID]).then(result => { @@ -238,8 +280,8 @@ confirmDepositFLO.checkTx = function(sender, txid) { function withdrawFLO(floID, amount) { return new Promise((resolve, reject) => { - if (!floID || !floCrypto.validateAddr(floID)) - return reject(INVALID("Invalid FLO ID")); + if (!floCrypto.validateAddr(floID)) + return reject(INVALID(`Invalid floID (${floID})`)); else if (typeof amount !== "number" || amount <= 0) return reject(INVALID(`Invalid amount (${amount})`)); getAssetBalance.check(floID, "FLO", amount).then(_ => { @@ -372,8 +414,8 @@ confirmDepositToken.checkTx = function(sender, txid) { function withdrawToken(floID, token, amount) { return new Promise((resolve, reject) => { - if (!floID || !floCrypto.validateAddr(floID)) - return reject(INVALID("Invalid FLO ID")); + if (!floCrypto.validateAddr(floID)) + return reject(INVALID(`Invalid floID (${floID})`)); else if (typeof amount !== "number" || amount <= 0) return reject(INVALID(`Invalid amount (${amount})`)); else if ((!assetList.includes(token) && token !== floGlobals.currency) || token === "FLO") @@ -454,6 +496,7 @@ module.exports = { addSellOrder, cancelOrder, getAccountDetails, + transferToken, depositFLO, withdrawFLO, depositToken, diff --git a/src/request.js b/src/request.js index f9a8cd2..132faaa 100644 --- a/src/request.js +++ b/src/request.js @@ -165,18 +165,17 @@ function PlaceSellOrder(req, res) { min_price: data.min_price, timestamp: data.timestamp }, data.sign, data.floID).then(req_str => { - 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'); - }).catch(error => { - if (error instanceof INVALID) - res.status(INVALID.e_code).send(error.message); - else { - console.error(error); - res.status(INTERNAL.e_code).send("Order placement failed! Try again later!"); - } - }); + market.addSellOrder(data.floID, data.asset, data.quantity, data.min_price).then(result => { + storeRequest(data.floID, req_str, data.sign); + res.send(result); + }).catch(error => { + if (error instanceof INVALID) + res.status(INVALID.e_code).send(error.message); + else { + console.error(error); + res.status(INTERNAL.e_code).send("Order placement failed! Try again later!"); + } + }); }).catch(error => { if (error instanceof INVALID) res.status(INVALID.e_code).send(error.message); @@ -196,18 +195,17 @@ function PlaceBuyOrder(req, res) { max_price: data.max_price, timestamp: data.timestamp }, data.sign, data.floID).then(req_str => { - 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'); - }).catch(error => { - if (error instanceof INVALID) - res.status(INVALID.e_code).send(error.message); - else { - console.error(error); - res.status(INTERNAL.e_code).send("Order placement failed! Try again later!"); - } - }); + market.addBuyOrder(data.floID, data.asset, data.quantity, data.max_price).then(result => { + storeRequest(data.floID, req_str, data.sign); + res.send(result); + }).catch(error => { + if (error instanceof INVALID) + res.status(INVALID.e_code).send(error.message); + else { + console.error(error); + res.status(INTERNAL.e_code).send("Order placement failed! Try again later!"); + } + }); }).catch(error => { if (error instanceof INVALID) res.status(INVALID.e_code).send(error.message); @@ -226,18 +224,47 @@ function CancelOrder(req, res) { id: data.orderID, timestamp: data.timestamp }, data.sign, data.floID).then(req_str => { - market.cancelOrder(data.orderType, data.orderID, data.floID) - .then(result => { - storeRequest(data.floID, req_str, data.sign); - res.send(result); - }).catch(error => { - if (error instanceof INVALID) - res.status(INVALID.e_code).send(error.message); - else { - console.error(error); - res.status(INTERNAL.e_code).send("Order cancellation failed! Try again later!"); - } - }); + market.cancelOrder(data.orderType, data.orderID, data.floID).then(result => { + storeRequest(data.floID, req_str, data.sign); + res.send(result); + }).catch(error => { + if (error instanceof INVALID) + res.status(INVALID.e_code).send(error.message); + else { + console.error(error); + res.status(INTERNAL.e_code).send("Order cancellation failed! Try again later!"); + } + }); + }).catch(error => { + if (error instanceof INVALID) + res.status(INVALID.e_code).send(error.message); + else { + console.error(error); + res.status(INTERNAL.e_code).send("Request processing failed! Try again later!"); + } + }); +} + +function TransferToken(req, res) { + let data = req.body; + validateRequestFromFloID({ + type: "transfer_token", + receiver: data.receiver, + token: data.token, + amount: data.amount, + timestamp: data.timestamp + }, data.sign, data.floID).then(req_str => { + market.transferToken(data.floID, data.receiver, data.token, data.amount).then(result => { + storeRequest(data.floID, req_str, data.sign); + res.send(result); + }).catch(error => { + if (error instanceof INVALID) + res.status(INVALID.e_code).send(error.message); + else { + console.error(error); + res.status(INTERNAL.e_code).send("Token Transfer failed! Try again later!"); + } + }); }).catch(error => { if (error instanceof INVALID) res.status(INVALID.e_code).send(error.message); @@ -264,7 +291,7 @@ function ListBuyOrders(req, res) { function ListTransactions(req, res) { //TODO: Limit size (recent) - DB.query("SELECT * FROM TransactionHistory ORDER BY tx_time DESC") + DB.query("SELECT * FROM TradeTransactions ORDER BY tx_time DESC") .then(result => res.send(result)) .catch(error => res.status(INTERNAL.e_code).send("Try again later!")); } @@ -301,7 +328,7 @@ function Account(req, res) { function DepositFLO(req, res) { let data = req.body; validateRequestFromFloID({ - type: "deposit_FLO", + type: "deposit_flo", txid: data.txid, timestamp: data.timestamp }, data.sign, data.floID).then(req_str => { @@ -329,7 +356,7 @@ function DepositFLO(req, res) { function WithdrawFLO(req, res) { let data = req.body; validateRequestFromFloID({ - type: "withdraw_FLO", + type: "withdraw_flo", amount: data.amount, timestamp: data.timestamp }, data.sign, data.floID).then(req_str => { @@ -357,7 +384,7 @@ function WithdrawFLO(req, res) { function DepositToken(req, res) { let data = req.body; validateRequestFromFloID({ - type: "deposit_Token", + type: "deposit_token", txid: data.txid, timestamp: data.timestamp }, data.sign, data.floID).then(req_str => { @@ -385,7 +412,7 @@ function DepositToken(req, res) { function WithdrawToken(req, res) { let data = req.body; validateRequestFromFloID({ - type: "withdraw_Token", + type: "withdraw_token", token: data.token, amount: data.amount, timestamp: data.timestamp @@ -416,7 +443,7 @@ function addUserTag(req, res) { if (!trustedIDs.includes(data.floID)) return res.status(INVALID.e_code).send("Access Denied"); validateRequestFromFloID({ - command: "add_Tag", + type: "add_tag", user: data.user, tag: data.tag, timestamp: data.timestamp @@ -448,7 +475,7 @@ function removeUserTag(req, res) { return res.status(INVALID.e_code).send("Access Denied"); else validateRequestFromFloID({ - command: "remove_Tag", + type: "remove_tag", user: data.user, tag: data.tag, timestamp: data.timestamp @@ -482,6 +509,7 @@ module.exports = { PlaceBuyOrder, PlaceSellOrder, CancelOrder, + TransferToken, ListSellOrders, ListBuyOrders, ListTransactions, diff --git a/src/set_globals.js b/src/set_globals.js index f402c37..ae8f846 100644 --- a/src/set_globals.js +++ b/src/set_globals.js @@ -2,6 +2,16 @@ //fetch for node js (used in floBlockchainAPI.js) global.fetch = require("node-fetch"); +global.convertDateToString = function(timestamp) { + let date = new Date(timestamp); + return date.getFullYear() + '-' + + ('00' + (date.getMonth() + 1)).slice(-2) + '-' + + ('00' + date.getDate()).slice(-2) + ' ' + + ('00' + date.getHours()).slice(-2) + ':' + + ('00' + date.getMinutes()).slice(-2) + ':' + + ('00' + date.getSeconds()).slice(-2); +} + //Set browser paramaters from param.json (or param-default.json) var param; try {