From ec718a3c4ed262962b5f932368043ab2297f7f81 Mon Sep 17 00:00:00 2001 From: sairajzero Date: Sun, 23 Apr 2023 23:13:21 +0530 Subject: [PATCH] Adding bunkTransferTokens - Added bunkTransferTokens: bulk transfer tokens to multiple receivers - usage: floWebWallet.bunkTransferTokens(sender, privKey, token, receivers) sender: floID of sender privKey: private key of sender token: token to send receivers: an object representing receiver floID and amount ie, {receiverID1: amount1, receiverID2: amount2....} eg: {Fxyz: 123, Fpqr:321, Fabc: 987} --- scripts/flo-webwallet.js | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/scripts/flo-webwallet.js b/scripts/flo-webwallet.js index feefb20..cb6ea43 100644 --- a/scripts/flo-webwallet.js +++ b/scripts/flo-webwallet.js @@ -110,4 +110,85 @@ }) } + function waitForConfirmation(txid, max_retry = -1, retry_timeout = 20) { + return new Promise((resolve, reject) => { + setTimeout(function () { + floBlockchainAPI.getTx(txid).then(tx => { + if (!tx) + return reject("Transaction not found"); + if (tx.confirmations) + return resolve(tx); + else if (max_retry === 0) //no more retries + return reject(false); + else { + max_retry = max_retry < 0 ? -1 : max_retry - 1; //decrease retry count (unless infinite retries) + waitForConfirmation(txid, max_retry, retry_timeout) + .then(result => resolve(result)) + .catch(error => reject(error)) + } + }).catch(error => reject(error)) + }, retry_timeout * 1000) + }) + } + + function sendRawTransaction(receiver, utxo, vout, scriptPubKey, data, wif) { + var trx = bitjs.transaction(); + trx.addinput(utxo, vout, scriptPubKey) + trx.addoutput(receiver, floBlockchainAPI.sendAmt); + trx.addflodata(data); + var signedTxHash = trx.sign(wif, 1); + return floBlockchainAPI.broadcastTx(signedTxHash); + } + + function sendTokens_raw(privKey, receiverID, token, amount, utxo, vout, scriptPubKey) { + return new Promise((resolve, reject) => { + sendRawTransaction(receiverID, utxo, vout, scriptPubKey, `send ${amount} ${token}#`, privKey) + .then(txid => resolve([receiverID, txid])) + .catch(error => reject([receiverID, error])) + }) + } + + //bulk transfer tokens + floWebWallet.bunkTransferTokens = function (sender, privKey, token, receivers) { + return new Promise((resolve, reject) => { + if (typeof receivers !== 'object') + return reject("receivers must be object in format {receiver1: amount1, receiver2:amount2...}") + + let receiver_list = Object.keys(receivers), amount_list = Object.values(receivers); + let invalidReceivers = receiver_list.filter(id => !floCrypto.validateFloID(id)); + let invalidAmount = amount_list.filter(val => typeof val !== 'number' || val <= 0); + if (invalidReceivers.length) + return reject(`Invalid receivers: ${invalidReceivers}`); + else if (invalidAmount.length) + return reject(`Invalid amounts: ${invalidAmount}`); + + //check for token balance + floTokenAPI.getBalance(sender, token).then(token_balance => { + let total_token_amout = amount_list.reduce((a, e) => a + e, 0); + if (total_token_amout > token_balance) + return reject(`Insufficient ${token}# balance`); + + //split utxos + floBlockchainAPI.splitUTXOs(sender, privKey, receiver_list.length).then(split_txid => { + //wait for the split utxo to get confirmation + waitForConfirmation(split_txid).then(split_tx => { + //send tokens using the split-utxo + var scriptPubKey = split_tx.vout[0].scriptPubKey.hex; + let promises = []; + for (let i in receiver_list) + promises.push(sendTokens_raw(privKey, receiver_list[i], token, amount_list[i], split_txid, i, scriptPubKey)); + Promise.allSettled(promises).then(results => { + let success = Object.fromEntries(results.filter(r => r.status == 'fulfilled').map(r => r.value)); + let failed = Object.fromEntries(results.filter(r => r.status == 'rejected').map(r => r.reason)); + resolve(success, failed); + }) + }).catch(error => reject(error)) + }).catch(error => reject(error)) + + }).catch(error => reject(error)) + + + }) + } + })(window.floWebWallet = {}); \ No newline at end of file