Transfer transactions now support one-to-many
- receiver parameter now requires an object in the format
{floID1: amount1, floID2: amount2 ...}
- Transaction hash (id) for both trade and transfer transactions are now generated using SHA of JSON-string object
- Updated schema for one-to-many TransferTransactions
This commit is contained in:
parent
f59c6b3f2a
commit
1823a46a98
@ -157,9 +157,9 @@ CREATE TABLE PriceHistory (
|
|||||||
CREATE TABLE TransferTransactions (
|
CREATE TABLE TransferTransactions (
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
sender CHAR(34) NOT NULL,
|
sender CHAR(34) NOT NULL,
|
||||||
receiver CHAR(34) NOT NULL,
|
receiver TEXT NOT NULL,
|
||||||
token VARCHAR(64) NOT NULL,
|
token VARCHAR(64) NOT NULL,
|
||||||
amount FLOAT NOT NULL,
|
totalAmount FLOAT NOT NULL,
|
||||||
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
tx_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
txid VARCHAR(66) NOT NULL,
|
txid VARCHAR(66) NOT NULL,
|
||||||
KEY(id),
|
KEY(id),
|
||||||
|
|||||||
@ -396,26 +396,35 @@ function cancelOrder(type, id, floID, proxySecret) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function transferToken(receiver, token, amount, floID, proxySecret) {
|
//receiver should be object eg {floID1: amount1, floID2: amount2 ...}
|
||||||
|
function transferToken(receiver, token, floID, proxySecret) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!floCrypto.validateAddr(receiver))
|
if (typeof receiver !== Object || receiver === null)
|
||||||
return reject(INVALID(`Invalid receiver (${receiver})`));
|
return reject("Invalid receiver: parameter is not an object");
|
||||||
else if (typeof amount !== "number" || amount <= 0)
|
let invalidIDs = [],
|
||||||
return reject(`Invalid amount (${amount})`);
|
invalidAmt = [];
|
||||||
|
for (let f in receiver) {
|
||||||
|
if (!floCrypto.validateAddr(f))
|
||||||
|
invalidIDs.push(f);
|
||||||
|
else if (typeof receiver[f] !== "number" || receiver[f] <= 0)
|
||||||
|
invalidAmt.push(receiver[f])
|
||||||
|
}
|
||||||
|
if (invalidIDs.length)
|
||||||
|
return reject(INVALID(`Invalid receiver (${invalidIDs})`));
|
||||||
|
else if (invalidAmt.length)
|
||||||
|
return reject(`Invalid amount (${invalidAmt})`);
|
||||||
let request = {
|
let request = {
|
||||||
floID: floID,
|
floID: floID,
|
||||||
token: token,
|
token: token,
|
||||||
receiver: receiver,
|
receiver: receiver,
|
||||||
amount: amount,
|
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
};
|
};
|
||||||
if (floCrypto.getFloID(proxySecret) === floID) //Direct signing (without proxy)
|
if (floCrypto.getFloID(proxySecret) === floID) //Direct signing (without proxy)
|
||||||
request.pubKey = floCrypto.getPubKeyHex(proxySecret);
|
request.pubKey = floCrypto.getPubKeyHex(proxySecret);
|
||||||
request.sign = signRequest({
|
request.sign = signRequest({
|
||||||
type: "transfer_token",
|
type: "transfer_token",
|
||||||
receiver: receiver,
|
receiver: JSON.stringify(receiver),
|
||||||
token: token,
|
token: token,
|
||||||
amount: amount,
|
|
||||||
timestamp: request.timestamp
|
timestamp: request.timestamp
|
||||||
}, proxySecret);
|
}, proxySecret);
|
||||||
console.debug(request);
|
console.debug(request);
|
||||||
|
|||||||
@ -118,7 +118,14 @@ function updateBalance(seller_best, buyer_best, txQueries, asset, cur_price, qua
|
|||||||
txQueries.push(["INSERT INTO Vault(floID, asset, base, quantity) VALUES (?, ?, ?, ?)", [buyer_best.floID, asset, cur_price, quantity]])
|
txQueries.push(["INSERT INTO Vault(floID, asset, base, quantity) VALUES (?, ?, ?, ?)", [buyer_best.floID, asset, cur_price, quantity]])
|
||||||
//Record transaction
|
//Record transaction
|
||||||
let time = Date.now();
|
let time = Date.now();
|
||||||
let hash = TRADE_HASH_PREFIX + Crypto.SHA256([time, seller_best.floID, buyer_best.floID, asset, quantity, cur_price].join("|"));
|
let hash = TRADE_HASH_PREFIX + Crypto.SHA256(JSON.stringify({
|
||||||
|
seller: seller_best.floID,
|
||||||
|
buyer: buyer_best.floID,
|
||||||
|
asset: asset,
|
||||||
|
quantity: quantity,
|
||||||
|
unitValue: cur_price,
|
||||||
|
tx_time: time,
|
||||||
|
}));
|
||||||
txQueries.push([
|
txQueries.push([
|
||||||
"INSERT INTO TradeTransactions (seller, buyer, asset, quantity, unitValue, tx_time, txid) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
"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]
|
[seller_best.floID, buyer_best.floID, asset, quantity, cur_price, global.convertDateToString(time), hash]
|
||||||
|
|||||||
@ -190,39 +190,56 @@ function getTransactionDetails(txid) {
|
|||||||
if (result.length) {
|
if (result.length) {
|
||||||
let details = result[0];
|
let details = result[0];
|
||||||
details.type = type;
|
details.type = type;
|
||||||
|
if (tableName === 'TransferTransactions') //As json object is stored for receiver in transfer (to support one-to-many)
|
||||||
|
details.receiver = JSON.parse(details.receiver);
|
||||||
resolve(details);
|
resolve(details);
|
||||||
} else
|
} else
|
||||||
reject(INVALID("Transaction not found"));
|
reject(INVALID("Transaction not found"));
|
||||||
}).catch(error => reject(error))
|
}).catch(error => reject(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
function transferToken(sender, receiver, token, amount) {
|
function transferToken(sender, receivers, token) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (floCrypto.validateAddr(sender))
|
if (floCrypto.validateAddr(sender))
|
||||||
return reject(INVALID(`Invalid sender (${sender})`));
|
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))
|
else if (token !== floGlobals.currency && !assetList.includes(token))
|
||||||
return reject(INVALID(`Invalid token (${token})`));
|
reject(INVALID(`Invalid token (${token})`));
|
||||||
getAssetBalance.check(senderID, token, amount).then(_ => {
|
else {
|
||||||
consumeAsset(sender, token, amount).then(txQueries => {
|
let invalidIDs = [],
|
||||||
if (token === floGlobals.currency)
|
totalAmount = 0;
|
||||||
txQueries.push(["INSERT INTO Cash (floID, balance) VALUE (?, ?) ON DUPLICATE KEY UPDATE balance=balance+?", [receiver, amount, amount]]);
|
for (let floID in receivers)
|
||||||
|
if (!floCrypto.validateAddr(floID))
|
||||||
|
invalidIDs.push(floID);
|
||||||
else
|
else
|
||||||
txQueries.push(["INSERT INTO Vault(floID, quantity) VALUES (?, ?)", [receiver, amount]]);
|
totalAmount += receivers[floID];
|
||||||
let time = Date.now();
|
if (invalidIDs.length)
|
||||||
let hash = TRANSFER_HASH_PREFIX + Crypto.SHA256([time, sender, receiver, token, amount].join("|"));
|
reject(INVALID(`Invalid receiver (${invalidIDs})`));
|
||||||
txQueries.push([
|
else getAssetBalance.check(senderID, token, totalAmount).then(_ => {
|
||||||
"INSERT INTO TransferTransactions (sender, receiver, token, amount, tx_time, txid)",
|
consumeAsset(sender, token, totalAmount).then(txQueries => {
|
||||||
[sender, receiver, token, amount, global.convertDateToString(time), hash]
|
if (token === floGlobals.currency)
|
||||||
]);
|
for (let floID in receivers)
|
||||||
DB.transaction(txQueries)
|
txQueries.push(["INSERT INTO Cash (floID, balance) VALUE (?, ?) ON DUPLICATE KEY UPDATE balance=balance+?", [floID, receivers[floID], receivers[floID]]]);
|
||||||
.then(result => resolve(hash))
|
else
|
||||||
.catch(error => reject(error))
|
for (let floID in receivers)
|
||||||
|
txQueries.push(["INSERT INTO Vault(floID, quantity) VALUES (?, ?)", [floID, receivers[floID]]]);
|
||||||
|
let time = Date.now();
|
||||||
|
let hash = TRANSFER_HASH_PREFIX + Crypto.SHA256(JSON.stringify({
|
||||||
|
sender: sender,
|
||||||
|
receiver: receivers,
|
||||||
|
token: token,
|
||||||
|
totalAmount: totalAmount,
|
||||||
|
tx_time: time,
|
||||||
|
}));
|
||||||
|
txQueries.push([
|
||||||
|
"INSERT INTO TransferTransactions (sender, receiver, token, totalAmount, tx_time, txid)",
|
||||||
|
[sender, JSON.stringify(receiver), token, totalAmount, 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))
|
||||||
}).catch(error => reject(error))
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -275,12 +275,11 @@ function TransferToken(req, res) {
|
|||||||
let data = req.body;
|
let data = req.body;
|
||||||
validateRequest({
|
validateRequest({
|
||||||
type: "transfer_token",
|
type: "transfer_token",
|
||||||
receiver: data.receiver,
|
receiver: JSON.stringify(data.receiver),
|
||||||
token: data.token,
|
token: data.token,
|
||||||
amount: data.amount,
|
|
||||||
timestamp: data.timestamp
|
timestamp: data.timestamp
|
||||||
}, data.sign, data.floID, data.pubKey).then(req_str => {
|
}, data.sign, data.floID, data.pubKey).then(req_str => {
|
||||||
market.transferToken(data.floID, data.receiver, data.token, data.amount).then(result => {
|
market.transferToken(data.floID, data.receiver, data.token).then(result => {
|
||||||
storeRequest(data.floID, req_str, data.sign, !data.pubKey);
|
storeRequest(data.floID, req_str, data.sign, !data.pubKey);
|
||||||
res.send(result);
|
res.send(result);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user