Adding transfer token feature
Transfer tokens - Added transferToken: Users can directly transfer tokens (including FLO) to other registered users. - Updated schema changes for the above requirement. - Trade transactions and transfer transactions will generate a txid (using SHA256). Other changes - changed all signing type to lowercase
This commit is contained in:
parent
136ba68b42
commit
0520791696
@ -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;
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", [
|
||||
|
||||
@ -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 => {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -165,10 +165,9 @@ 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 => {
|
||||
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');
|
||||
res.send(result);
|
||||
}).catch(error => {
|
||||
if (error instanceof INVALID)
|
||||
res.status(INVALID.e_code).send(error.message);
|
||||
@ -196,10 +195,9 @@ 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 => {
|
||||
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');
|
||||
res.send(result);
|
||||
}).catch(error => {
|
||||
if (error instanceof INVALID)
|
||||
res.status(INVALID.e_code).send(error.message);
|
||||
@ -226,8 +224,7 @@ 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 => {
|
||||
market.cancelOrder(data.orderType, data.orderID, data.floID).then(result => {
|
||||
storeRequest(data.floID, req_str, data.sign);
|
||||
res.send(result);
|
||||
}).catch(error => {
|
||||
@ -248,6 +245,36 @@ function CancelOrder(req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
else {
|
||||
console.error(error);
|
||||
res.status(INTERNAL.e_code).send("Request processing failed! Try again later!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function ListSellOrders(req, res) {
|
||||
//TODO: Limit size (best)
|
||||
DB.query("SELECT * FROM SellOrder ORDER BY time_placed")
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user