From a569adcb746ef9c6b0bbeb0640ef29dcaf0f79c5 Mon Sep 17 00:00:00 2001 From: sairajzero Date: Sat, 25 Apr 2020 17:54:13 +0530 Subject: [PATCH] Adding mergeUTXOs, sendTxMulti and writeDataMulti mergeUTXOs: /merge all UTXOs of a given floID into a single UTXO sendTxMulti: Send Tx from (and/or) to multiple floID writeDataMulti: Write data into blockchain from (and/or) to multiple floID --- standard_Operations.html | 186 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 181 insertions(+), 5 deletions(-) diff --git a/standard_Operations.html b/standard_Operations.html index 4ed3dc4..d1f9ff5 100644 --- a/standard_Operations.html +++ b/standard_Operations.html @@ -7360,22 +7360,24 @@ Bitcoin.Util = { }, //Write Data into blockchain - writeData: function (senderAddr, Data, PrivKey, receiverAddr = floGlobals.adminID) { + writeData: function (senderAddr, data, privKey, receiverAddr = floGlobals.adminID) { return new Promise((resolve, reject) => { - this.sendTx(senderAddr, receiverAddr, floGlobals.sendAmt, PrivKey, Data) + if (typeof data != "string") + data = JSON.stringify(data); + this.sendTx(senderAddr, receiverAddr, floGlobals.sendAmt, privKey, data) .then(txid => resolve(txid)) .catch(error => reject(error)) }); }, //Send Tx to blockchain - sendTx: function (senderAddr, receiverAddr, sendAmt, PrivKey, floData = '') { + sendTx: function (senderAddr, receiverAddr, sendAmt, privKey, floData = '') { return new Promise((resolve, reject) => { if (!floCrypto.validateAddr(senderAddr)) reject(`Invalid address : ${senderAddr}`); else if (!floCrypto.validateAddr(receiverAddr)) reject(`Invalid address : ${receiverAddr}`); - if (PrivKey.length < 1 || !floCrypto.verifyPrivKey(PrivKey, senderAddr)) + if (privKey.length < 1 || !floCrypto.verifyPrivKey(privKey, senderAddr)) reject("Invalid Private key!"); else if (typeof sendAmt !== 'number' || sendAmt <= 0) reject(`Invalid sendAmt : ${sendAmt}`); @@ -7400,7 +7402,7 @@ Bitcoin.Util = { if (change > 0) trx.addoutput(senderAddr, change); trx.addflodata(floData); - var signedTxHash = trx.sign(PrivKey, 1); + var signedTxHash = trx.sign(privKey, 1); this.broadcastTx(signedTxHash) .then(txid => resolve(txid)) .catch(error => reject(error)) @@ -7410,11 +7412,185 @@ Bitcoin.Util = { }); }, + //merge all UTXOs of a given floID into a single UTXO + mergeUTXOs: function (floID, privKey, floData = '') { + return new Promise((resolve, reject) => { + if (!floCrypto.validateAddr(floID)) + return reject(`Invalid floID`); + if (!floCrypto.verifyPrivKey(privKey, floID)) + return reject("Invalid Private Key") + + var trx = bitjs.transaction(); + var utxoAmt = 0.0; + var fee = floGlobals.fee; + this.promisedAPI(`api/addr/${floID}/utxo`).then(utxos => { + for (var i = utxos.length - 1; i >= 0; i--) { + if (utxos[i].confirmations) { + trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i] + .scriptPubKey) + utxoAmt += utxos[i].amount; + } + } + trx.addoutput(floID, utxoAmt - fee); + trx.addflodata(floData); + var signedTxHash = trx.sign(privKey, 1); + this.broadcastTx(signedTxHash) + .then(txid => resolve(txid)) + .catch(error => reject(error)) + }).catch(error => reject(error)) + }) + }, + + /**Write data into blockchain from (and/or) to multiple floID + * @param {Object or Array} senders List of sender floIDs with respective private-key (or) Array of sender private-keys + * @param {string} data FLO data of the txn + * @param {Array} receivers Array of receivers + * @param {float} sendAmt (optional) amount to be sent to receivers (default value: floGlobals.sendAmt) + * @return {Promise} + */ + writeDataMulti: function (senders, data, receivers = [floGlobals.adminID], sendAmt = floGlobals.sendAmt) { + return new Promise((resolve, reject) => { + if (Array.isArray(senders)) { + let tmp = {} + senders.forEach(key => { + if (key) { + let floID = floCrypto.getFloIDfromPubkeyHex(floCrypto.getPubKeyHex( + key)) + tmp[floID] = key; + } + }); + senders = tmp; + } + if (!Array.isArray(receivers)) + return reject("Invalid receivers: Receivers must be Array") + else { + let tmp = {} + receivers.forEach(floID => tmp[floID] = sendAmt) + receivers = tmp; + } + if (typeof data != "string") + data = JSON.stringify(data); + this.sendTxMulti(senders, receivers, data) + .then(txid => resolve(txid)) + .catch(error => reject(error)) + }) + }, + + /**Send Tx from (and/or) to multiple floID + * @param {Object} senders List of sender floIDs with respective private-key + * @param {Object} receivers List of receivers with respective amount to be sent + * @param {string} floData FLO data of the txn + * @return {Promise} + */ + sendTxMulti: function (senders, receivers, floData = '') { + return new Promise((resolve, reject) => { + let invalids = { + InvalidSenderIDs: [], + InvalidPrivKeysFor: [], + InvalidReceiverIDs: [], + InvalidAmountFor: [], + InvalidChangeAddress: [] + } + for (floID in senders) { + if (!floCrypto.validateAddr(floID)) + invalids.InvalidSenderIDs.push(floID) + else if (!floCrypto.verifyPrivKey(senders[floID], floID)) + invalids.InvalidPrivKeysFor.push(floID) + } + for (floID in receivers) { + if (!floCrypto.validateAddr(floID)) + invalids.InvalidReceiverIDs.push(floID) + if (typeof receivers[floID] !== 'number' || receivers[floID] <= 0) + invalids.InvalidAmountFor.push(floID) + } + for (i in invalids) + if (!invalids[i].length) + delete invalids[i]; + if (Object.keys(invalids).length) + return reject(invalids); + //Get balance of senders + let promises = [] + for (floID in senders) + promises.push(this.getBalance(floID)) + Promise.all(promises).then(results => { + console.log(results) + let totalBalance = 0, + fee = floGlobals.fee, + balance = {}; + invalids.InsufficientBalance = []; + for (floID in senders) { + balance[floID] = parseFloat(results.shift()); + if (isNaN(balance[floID]) || balance[floID] <= fee) + invalids.InsufficientBalance.push(floID) + totalBalance += balance[floID]; + } + if (invalids.InsufficientBalance.length) + return reject(invalids) + delete invalids.InsufficientBalance; + console.log(balance); + let totalSendAmt = fee; + for (floID in receivers) + totalSendAmt += receivers[floID]; + if (totalBalance < totalSendAmt) + return reject("Insufficient total Balance") + let promises = [] + for (floID in senders) + promises.push(this.promisedAPI(`api/addr/${floID}/utxo`)) + Promise.all(promises).then(results => { + let tmp = {}; + let wifSeq = []; + var trx = bitjs.transaction(); + for (floID in senders) { + let utxos = results.shift(); + let ratio = (balance[floID] / totalBalance).toFixed(2); + let sendAmt = totalSendAmt * ratio; + let wif = senders[floID] + let utxoAmt = 0.0; + for (let i = utxos.length - 1; + (i >= 0) && (utxoAmt < sendAmt); i--) { + if (utxos[i].confirmations) { + trx.addinput(utxos[i].txid, utxos[i].vout, utxos[i] + .scriptPubKey) + wifSeq.push(wif); + utxoAmt += utxos[i].amount; + } + } + if (utxoAmt < sendAmt) + return reject("Insufficient balance:" + floID); + let change = (utxoAmt - sendAmt).toFixed(5); + if (change > 0) + trx.addoutput(floID, change); + + tmp[floID] = { + ratio: ratio, + sendAmt: sendAmt, + utxoAmt: utxoAmt, + change: change + } + } + for (floID in receivers) + trx.addoutput(floID, receivers[floID]); + trx.addflodata(floData); + for (let i = 0; i < wifSeq.length; i++) + trx.signinput(i, wifSeq[i], 1); + var signedTxHash = trx.serialize(); + console.log(signedTxHash), + console.log(trx) + console.log(tmp) + this.broadcastTx(signedTxHash) + .then(txid => resolve(txid)) + .catch(error => reject(error)) + }).catch(error => reject(error)) + }).catch(error => reject(error)) + }) + }, + //Broadcast signed Tx in blockchain using API broadcastTx: function (signedTxHash) { return new Promise((resolve, reject) => { var request = new XMLHttpRequest(); var url = this.util.serverList[this.util.curPos] + 'api/tx/send'; + console.log(url) if (signedTxHash.length < 1) reject("Empty Signature"); else {