diff --git a/index.html b/index.html index bb91364..f9ac82e 100644 --- a/index.html +++ b/index.html @@ -16686,7 +16686,7 @@ // Check how much cryptos the user can withdraw let withdrawer_btc_id = `${params.trader_flo_address}_${params.product}`; readDB("crypto_balances", withdrawer_btc_id).then( - function(btc_balance_res) { + async function(btc_balance_res) { if ( typeof btc_balance_res == "object" && typeof btc_balance_res.trader_flo_address == @@ -16707,17 +16707,11 @@ ) { // Now details of Bitcoins can be sent to withdrawer - /**************************************************************************** - ***********IMPORTANT: CHANGE RECEIVING ADDRESS TO BTC THAN FLO HERE********** - ***********AND DO SOMETHING ABOUT PRIVATE KEY BELOW************************** - ****************************************************************************/ let sum_total_btc = 0; let valid_utxo_list = []; let receiverBTCAddress = params.receivinAddress.trim(); - readAllDB("deposit").then(function( - deposit_list - ) { + const deposit_list = await readAllDB("deposit"); if ( typeof deposit_list == "object" && deposit_list.length > 0 @@ -16733,6 +16727,13 @@ ) && params.product == deposit_dl.product )) { + // Deposited Bitcoin is under process + deposit_dl.status = 3; + await updateinDB( + "deposit", + deposit_dl, + deposit_dl.id + ); sum_total_btc += helper_functions.truncateDecimals( deposit_dl.bitcoinToBePaid ); @@ -16749,14 +16750,7 @@ let deposited_utxo_addr_list = {}; let idx = 0; for (const deposit_arr of valid_utxo_list) { - // Deposited Bitcoin is under process - deposit_arr.status = 3; - updateinDB( - "deposit", - deposit_arr, - deposit_arr.id - ); - + if(idx==valid_utxo_list.length-1) { deposited_utxo_addr_list[idx]=deposit_arr.btc_address; // save the address and id in a table @@ -16776,7 +16770,7 @@ timestamp: +new Date() }; - addDB("withdraw_btc", withdraw_btc_order_object); + await addDB("withdraw_btc", withdraw_btc_order_object); // Delete the withdraw crypto order after 30 mins anyway let withdraw_order_life = JSON.parse(localbitcoinplusplus.master_configurations.ordersLife); @@ -16798,7 +16792,9 @@ await updateinDB( "deposit", deposit_arr, - deposit_arr.id + deposit_arr.id, + false, + false ); return; } @@ -16830,7 +16826,7 @@ idx++; } } - }); + } else { err_msg = `Withdrawal request failed: You are trying to withdraw more ${params.product} than you have.`; err_response = { @@ -17187,48 +17183,38 @@ RM_RPC.filter_legit_requests( params.trader_flo_address, async function (is_valid_request) { - if (is_valid_request !== true) return false; - - if ( - typeof params.btc_private_key_array !== "object" || - typeof params.retrieve_pvtkey_req_id !== "object" - ) - return false; - - let rec_flo_id = - params.receiver_flo_address || - request.globalParams.receiverFloId; - if ( - typeof rec_flo_id == "undefined" || - rec_flo_id !== - localbitcoinplusplus.wallets.my_local_flo_address - ) - return; - - if (typeof params.db_inst !== "string") - throw new Error(`ERROR: No DB instance provided.`); - if ( - params.db_inst !== - localbitcoinplusplus.wallets.my_local_flo_address - ) return; - - let retrieve_pvtkey_req_id = params.retrieve_pvtkey_req_id; - let withdraw_id = params.withdraw_id; - try { - // let btc_private_key_object = params.btc_private_key_array; - // let btc_pk_shares_array = btc_private_key_object - // .map(pkChunks => { - // if (typeof pkChunks.private_key_chunk !== "undefined") - // return pkChunks.private_key_chunk.privateKeyChunks; - // }) - // .filter(val => val !== undefined); - // console.log(btc_pk_shares_array); + if (is_valid_request !== true) return false; + + if ( + typeof params.btc_private_key_array !== "object" + ) + return false; + + let rec_flo_id = + params.receiver_flo_address || + request.globalParams.receiverFloId; + if ( + typeof rec_flo_id == "undefined" || + rec_flo_id !== + localbitcoinplusplus.wallets.my_local_flo_address + ) + return; + + if (typeof params.db_inst !== "string") + throw new Error(`ERROR: No DB instance provided.`); + if ( + params.db_inst !== + localbitcoinplusplus.wallets.my_local_flo_address + ) return; + + const withdraw_id = params.withdraw_id; const withdraw_res = await readDB("withdraw_btc", withdraw_id); if (typeof withdraw_res == "object") { const withdrawer_crypto_bal_id = `${withdraw_res.trader_flo_address}_${withdraw_res.product}`; const withdrawer_crypto_bal_response = await readDB("crypto_balances", withdrawer_crypto_bal_id); + const withdrawer_crypto_bal_response_before_update = JSON.parse(JSON.stringify(withdrawer_crypto_bal_response)); if (typeof withdrawer_crypto_bal_response !== "object" || typeof withdrawer_crypto_bal_response.crypto_balance !== "number") { @@ -17276,303 +17262,282 @@ return false; } - const bal_url = `${explorer}/api/addr/${withdraw_res.utxo_addr}/balance`; - console.log(bal_url); - // Get the balance before sending the tx. It is important to get balance before // tx than to after because fetching balance after can return older or newer balance // on random events - let current_balance = await helper_functions.ajaxGet(bal_url); + let current_utxos_balance = 0; + const RM_WALLET = new localbitcoinplusplus.wallets; + let total_balance_promises = []; + for (const utxo_pk of params.btc_private_key_array) { + let utxo_addr = RM_WALLET.generateFloKeys(utxo_pk, withdraw_res.product).address; + const bal_url = `${explorer}/api/addr/${utxo_addr}/balance`; + total_balance_promises.push(helper_functions.ajaxGet(bal_url)); + } + let total_balance_promises_resp = await Promise.all(total_balance_promises); + current_utxos_balance = total_balance_promises_resp.reduce((acc, c) => acc + c, 0); + console.log(current_utxos_balance); - if(typeof current_balance !== "number" || current_balance<=0) { + if (typeof current_utxos_balance !== "number" || current_utxos_balance <= 0) { throw new Error( - "Failed to determine utxo balance of address "+withdraw_res.utxo_addr + "Failed to determine utxo balance of deposits in withdraw_id " + withdraw_res.id ); } - - const btc_reserves = await readDB("system_btc_reserves_private_keys", retrieve_pvtkey_req_id); - if (typeof btc_reserves == "object") { - // Ideally this line should never run. - if (btc_reserves.product !== withdraw_res.product) - throw new Error( - "Mismatch of assets in withdrawal request." - ); - await RM_TRADE.resolve_current_crypto_price_in_fiat( - withdraw_res.product, - withdraw_res.currency - ); - const EqCryptoWd = helper_functions.truncateDecimals(withdraw_res.receivingBTC); - //const EqCryptoWd = helper_functions.truncateDecimals(current_balance); + const totalWithdrawingAmount = helper_functions.truncateDecimals(withdraw_res.receivingBTC); - if (withdraw_res.receivingBTC > withdrawer_crypto_bal_response.crypto_balance) { - err_response = { - user_flo_addr: params.trader_flo_address, - msg: `You are withdrawing ${withdraw_res.product} more than your balance.` - } - reactor.dispatchEvent('message_for_user', err_response); - return false; + if (totalWithdrawingAmount > withdrawer_crypto_bal_response.crypto_balance) { + err_response = { + user_flo_addr: params.trader_flo_address, + msg: `You are withdrawing ${withdraw_res.product} more than your balance.` } + reactor.dispatchEvent('message_for_user', err_response); + return false; + } - let transaction_key = localbitcoinplusplus.actions - .master_decrypt(btc_reserves.supernode_transaction_key); - if(typeof transaction_key=="string") { - transaction_key = JSON.parse(transaction_key); - } - if (transaction_key.length > 0) { - let btc_private_key = RM_WALLET.rebuild_private_key( - btc_pk_shares_array, - transaction_key - ); - console.log(btc_private_key); + if (totalWithdrawingAmount > current_utxos_balance) { + err_response = { + user_flo_addr: params.trader_flo_address, + msg: `${withdraw_res.product} Withdrawal request failed: System does not have sufficient balance. + Please try later.` + } + reactor.dispatchEvent('message_for_user', err_response); + return false; + } - let withdrawingAmountInThisTx = helper_functions.truncateDecimals(withdraw_res.receivingBTC); - if(withdraw_res.receivingBTC>current_balance) { - withdrawingAmountInThisTx = current_balance; - } + // Deduct balance before sending crypto + withdrawer_crypto_bal_response.crypto_balance -= totalWithdrawingAmount; + withdrawer_crypto_bal_response.crypto_balance = + helper_functions.truncateDecimals(withdrawer_crypto_bal_response.crypto_balance); + const updated_crypto_balance = await updateinDB( + "crypto_balances", + withdrawer_crypto_bal_response, + withdrawer_crypto_bal_id + ); - RM_TRADE.sendTransaction( - withdraw_res.product, - withdraw_res.utxo_addr, - btc_private_key, - withdraw_res.receiverBTCAddress, - withdrawingAmountInThisTx, - withdraw_res.change_adress, - async function (res) { - console.log(res); - if (typeof res == "object") { - try { - let msg = ""; - if ( - typeof res.txid == "string" && - res.txid.length > 0 - ) { - resp_obj = JSON.parse(res.txid); - resp_txid = resp_obj.txid.result || resp_obj.txid; - msg = `Transaction Id for your withdrawn crypto asset: ${resp_txid}.`; + RM_TRADE.sendMultipleInputsTransaction( + withdraw_res.product, + params.btc_private_key_array, + withdraw_res.receiverBTCAddress, + totalWithdrawingAmount, + withdraw_res.change_adress, + async function (res) { + console.log(res); + try { + if (typeof res == "object") { + let msg = ""; + if ( + typeof res.txid == "string" && + res.txid.length > 0 + ) { + resp_obj = JSON.parse(res.txid); + resp_txid = resp_obj.txid.result || resp_obj.txid; + msg = `Transaction Id for your withdrawn crypto asset: ${resp_txid}.`; - const RM_RPC = new localbitcoinplusplus.rpc(); - RM_RPC.send_rpc - .call(this, "supernode_message", { - trader_flo_address: - withdraw_res.trader_flo_address, - receiver_flo_address: - withdraw_res.trader_flo_address, - server_msg: msg - }) - .then(server_response => - doSend(server_response) - ); + const RM_RPC = new localbitcoinplusplus.rpc(); + RM_RPC.send_rpc + .call(this, "supernode_message", { + trader_flo_address: + withdraw_res.trader_flo_address, + receiver_flo_address: + withdraw_res.trader_flo_address, + server_msg: msg + }) + .then(server_response => + doSend(server_response) + ); - withdrawer_crypto_bal_response.crypto_balance -= EqCryptoWd; - withdrawer_crypto_bal_response.crypto_balance = - helper_functions.truncateDecimals(withdrawer_crypto_bal_response.crypto_balance); - const updated_crypto_balance = await updateinDB( - "crypto_balances", - withdrawer_crypto_bal_response, - withdrawer_crypto_bal_id - ); - const res_obj_str = JSON.stringify(updated_crypto_balance); - const res_obj_hash = Crypto.SHA256(res_obj_str); - const res_obj_sign = RM_WALLET.sign( - res_obj_hash, - localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY - ); + const res_obj_str = JSON.stringify(updated_crypto_balance); + const res_obj_hash = Crypto.SHA256(res_obj_str); + const res_obj_sign = RM_WALLET.sign( + res_obj_hash, + localbitcoinplusplus.wallets.MY_SUPERNODE_PRIVATE_KEY + ); - const updateUserCryptoBalanceObject = { - updatedBTCBalanceObject: updated_crypto_balance, - updatedBTCBalanceObjectSign: res_obj_sign, - trader_flo_address: withdraw_res.trader_flo_address, - receiver_flo_address: withdraw_res.trader_flo_address - }; + const updateUserCryptoBalanceObject = { + updatedBTCBalanceObject: updated_crypto_balance, + updatedBTCBalanceObjectSign: res_obj_sign, + trader_flo_address: withdraw_res.trader_flo_address, + receiver_flo_address: withdraw_res.trader_flo_address + }; - RM_RPC.send_rpc( - "updateUserCryptoBalanceRequest", - updateUserCryptoBalanceObject - ).then( - updateUserCryptoBalanceRequestObject => - doSend(updateUserCryptoBalanceRequestObject) - ); + RM_RPC.send_rpc( + "updateUserCryptoBalanceRequest", + updateUserCryptoBalanceObject + ).then( + updateUserCryptoBalanceRequestObject => + doSend(updateUserCryptoBalanceRequestObject) + ); - // Check if there's BTC left in deposited BTC. If yes update its status to 2 else delete it + // Check if there's BTC left in deposited BTC. If yes update its status to 2 else delete it - /*********************************************************************************************************************************** - *******************CHECK ACTUAL BTC BALANCE HERE THROUGH AN API AND UPDATE DEPOSIT TABLE**************************************************** - ************************************************************************************************************************************/ + /*********************************************************************************************************************************** + *******************CHECK ACTUAL BTC BALANCE HERE THROUGH AN API AND UPDATE DEPOSIT TABLE**************************************************** + ************************************************************************************************************************************/ - const deposit_arr_resp = await readDBbyIndex( - "deposit", - "btc_address", - withdraw_res.utxo_addr - ); - if (typeof deposit_arr_resp[0] == "object") { - const deposit_arr = deposit_arr_resp[0]; - if ( - !isNaN(current_balance) && - parseFloat(current_balance) > 0 - ) { - current_balance = helper_functions.truncateDecimals( - current_balance / decimal - ); - } + for (const deposited_utxo_idx in withdraw_res.utxo_addr) { + let deposited_utxo_addr = withdraw_res.utxo_addr[deposited_utxo_idx]; - if ( - typeof current_balance == "number" - ) { - deposit_arr.bitcoinToBePaid = current_balance-EqCryptoWd; - btc_reserves.balance = current_balance-EqCryptoWd; - } else { - deposit_arr.bitcoinToBePaid -= EqCryptoWd; - btc_reserves.balance -= EqCryptoWd; - // Tx is not registered in Blocckhain yet. Refresh balance after 30 minutes - localbitcoinplusplus.actions.delay(1800000).then(() => - reactor.dispatchEvent("refresh_reserved_crypto_balances", params.trader_flo_address) - ); - } - - deposit_arr.bitcoinToBePaid = helper_functions.truncateDecimals(deposit_arr.bitcoinToBePaid); - btc_reserves.balance = helper_functions.truncateDecimals(btc_reserves.balance); - - if ( - deposit_arr.bitcoinToBePaid > 0 - ) { - // update deposits in db - deposit_arr.status = 2; // UTXO ready to be used again - const deposit_resp = await updateinDB( - "deposit", - deposit_arr, - deposit_arr.id - ); - // Update new balance in system_btc_reserves - const reserves_resp = await updateinDB( - "system_btc_reserves_private_keys", - btc_reserves, - btc_reserves.id - ); - - // Send the resp to backups - RM_RPC.send_rpc( - "update_deposited_crypto_instance", - { - deposit_data: deposit_resp, - btc_reserve_data: reserves_resp, - db_inst: params.db_inst, - trader_flo_address: - deposit_arr.trader_flo_address - } - ).then(delRequestObject => - doSend(delRequestObject) - ); - - // Do not delete these data instantly as the data - // may be required by a follow-up withdraw request - await localbitcoinplusplus.actions.delay(180000) - await removeinDB("withdraw_btc", withdraw_id); - - RM_RPC.send_rpc( - "delete_deposited_crypto_instance", - { - withdraw_btc_id: withdraw_id, - db_inst: params.db_inst, - trader_flo_address: - deposit_arr.trader_flo_address - } - ).then(delRequestObject => - doSend(delRequestObject) - ); - - // AND DO THE SAME ABOVE 2 IN BACKUP RECEIVE RPC - } else { - // Do not delete these data instantly as the data - // may be required by a follow-up withdraw request - await localbitcoinplusplus.actions.delay(180000); - - let p1 = removeinDB("deposit", deposit_arr.id); - let p2 = removeinDB("system_btc_reserves_private_keys", retrieve_pvtkey_req_id); - let p3 = removeinDB("withdraw_btc", withdraw_id); - - await Promise.all([p1, p2, p3]); - - RM_RPC.send_rpc( - "delete_deposited_crypto_instance", - { - deposit_id: - deposit_arr.id, - btc_reserve_id: retrieve_pvtkey_req_id, - withdraw_btc_id: withdraw_id, - db_inst: params.db_inst, - trader_flo_address: - deposit_arr.trader_flo_address - } - ).then(delRequestObject => - doSend(delRequestObject) - ); - - } - - return true; - } - - } else { - console.log(res); - throw new Errror(`ERROR: Failed to make transaction.`); - return false; - } - - } catch (error) { - console.warn(error); - err_response = { - user_flo_addr: params.trader_flo_address, - msg: `Withdraw of crypto failed. Network issue:- Please try again after 30 minutes.` - } - reactor.dispatchEvent('message_for_user', err_response); - // Do not delete these data instantly as the data - // may be required by a follow-up withdraw request - await localbitcoinplusplus.actions.delay(180000); - - // update deposits status back to 2 in db const deposit_arr_resp = await readDBbyIndex( "deposit", "btc_address", - withdraw_res.utxo_addr - ) + deposited_utxo_addr + ); if (typeof deposit_arr_resp[0] == "object") { - deposit_arr_resp[0].status = 2; // UTXO ready to be used again - await updateinDB( - "deposit", - deposit_arr_resp[0], - deposit_arr_resp[0].id - ); - } - await removeinDB("withdraw_btc", withdraw_id); + const deposit_arr = deposit_arr_resp[0]; + if ( + !isNaN(current_utxos_balance) && + parseFloat(current_utxos_balance) > 0 + ) { + current_utxos_balance = helper_functions.truncateDecimals( + current_utxos_balance / decimal + ); + } + if ( + typeof current_utxos_balance == "number" + ) { + deposit_arr.bitcoinToBePaid = current_utxos_balance - totalWithdrawingAmount; + } else { + throw new Error('current_utxos_balance is not a number'); + } + + deposit_arr.bitcoinToBePaid = helper_functions.truncateDecimals(deposit_arr.bitcoinToBePaid); + + if ( + deposit_arr.bitcoinToBePaid > 0 + ) { + // update deposits in db + deposit_arr.status = 2; // UTXO ready to be used again + const deposit_resp = await updateinDB( + "deposit", + deposit_arr, + deposit_arr.id + ); + + // Send the resp to backups + RM_RPC.send_rpc( + "update_deposited_crypto_instance", + { + deposit_data: deposit_resp, + db_inst: params.db_inst, + trader_flo_address: + deposit_arr.trader_flo_address + } + ).then(delRequestObject => + doSend(delRequestObject) + ); + + await removeinDB("withdraw_btc", withdraw_id); + + RM_RPC.send_rpc( + "delete_deposited_crypto_instance", + { + withdraw_btc_id: withdraw_id, + db_inst: params.db_inst, + trader_flo_address: + deposit_arr.trader_flo_address + } + ).then(delRequestObject => + doSend(delRequestObject) + ); + + // AND DO THE SAME ABOVE 2 IN BACKUP RECEIVE RPC + } else { + + let p1 = removeinDB("deposit", deposit_arr.id); + let p2 = removeinDB("withdraw_btc", withdraw_id); + + await Promise.all([p1, p2]); + + RM_RPC.send_rpc( + "delete_deposited_crypto_instance", + { + deposit_id: deposit_arr.id, + withdraw_btc_id: withdraw_id, + db_inst: params.db_inst, + trader_flo_address: + deposit_arr.trader_flo_address + } + ).then(delRequestObject => + doSend(delRequestObject) + ); + + } + + return true; + } } + + } else { + console.log(res); + throw new Errror(`ERROR: Failed to make transaction.`); + } + } else { + console.error("Waithdraw transaction is not an object"); + //throw new Errror(`ERROR: Failed to make transaction.`); + } + + } catch (error) { + console.warn(error); + err_response = { + user_flo_addr: params.trader_flo_address, + msg: `Withdraw of crypto failed. Network issue:- Please try again after 30 minutes.` + } + reactor.dispatchEvent('message_for_user', err_response); + + // update deposits status back to 2 in db + for (const deposited_utxo_idx in withdraw_res.utxo_addr) { + let deposited_utxo_addr = withdraw_res.utxo_addr[deposited_utxo_idx]; + const deposit_arr_resp = await readDBbyIndex( + "deposit", + "btc_address", + deposited_utxo_addr + ) + if (typeof deposit_arr_resp[0] == "object") { + deposit_arr_resp[0].status = 2; // UTXO ready to be used again + await updateinDB( + "deposit", + deposit_arr_resp[0], + deposit_arr_resp[0].id + ); } } - ); - } - } + await removeinDB("withdraw_btc", withdraw_id); + } + } + ); } } catch (error) { - - const withdraw_res = await readDB("withdraw_btc", withdraw_id); - // update deposits status back to 2 in db - const deposit_arr_resp = await readDBbyIndex( - "deposit", - "btc_address", - withdraw_res.utxo_addr - ) - if (typeof deposit_arr_resp[0] == "object") { - deposit_arr_resp[0].status = 2; // UTXO ready to be used again - await updateinDB( + + const withdraw_res = await readDB("withdraw_btc", params.withdraw_id); + for (const deposited_utxo_idx in withdraw_res.utxo_addr) { + let deposited_utxo_addr = withdraw_res.utxo_addr[deposited_utxo_idx]; + // update deposits status back to 2 in db + const deposit_arr_resp = await readDBbyIndex( "deposit", - deposit_arr_resp[0], - deposit_arr_resp[0].id - ); + "btc_address", + deposited_utxo_addr + ) + if (typeof deposit_arr_resp[0] == "object") { + deposit_arr_resp[0].status = 2; // UTXO ready to be used again + updateinDB( + "deposit", + deposit_arr_resp[0], + deposit_arr_resp[0].id + ); + } } - await removeinDB("withdraw_btc", withdraw_id); + removeinDB("withdraw_btc", params.withdraw_id); + // Revert user balance + updateinDB("crypto_balances", + withdrawer_crypto_bal_response_before_update, + withdrawer_crypto_bal_response_before_update.id, + false, + false + ); + throw new Error(error); } } @@ -18501,7 +18466,7 @@ const withdrawer_btc_id = `${params.trader_flo_address}_${params.product}`; backup_server_db_instance .backup_readDB("crypto_balances", withdrawer_btc_id) - .then(function(btc_balance_res) { + .then(async function(btc_balance_res) { if ( typeof btc_balance_res == "object" && typeof btc_balance_res.trader_flo_address == @@ -18522,11 +18487,6 @@ eqBTC <= withdrawer_btc_balance ) { // Now details of Bitcoins can be sent to withdrawer - - /**************************************************************************** - ***********IMPORTANT: CHANGE RECEIVING ADDRESS TO BTC THAN FLO HERE********** - ***********AND DO SOMETHING ABOUT PRIVATE KEY BELOW************************** - ****************************************************************************/ let sum_total_btc = 0; let valid_utxo_list = []; let receiverBTCAddress = params.receivinAddress.trim(); @@ -20862,6 +20822,170 @@ ) ); }, + + // Send transaction for multiple inputs and outputs + sendMultipleInputsTransaction( + crypto_type, + utxo_addr_wif, + receiver_address, + receiving_amount, + change_adress, + callback, + custom_floData = "" + ) { + let blockchain_explorer; + let miners_fee = 0.0003; + const miner_fee_obj = JSON.parse( + localbitcoinplusplus.master_configurations.miners_fee + ); + if (crypto_type == "BTC") { + blockchain_explorer = localbitcoinplusplus.server.btc_mainnet; + miners_fee = miner_fee_obj.btc; + } else if (crypto_type == "BTC_TEST") { + blockchain_explorer = localbitcoinplusplus.server.btc_testnet; + miners_fee = miner_fee_obj.btc; + } else if (crypto_type == "FLO") { + blockchain_explorer = localbitcoinplusplus.server.flo_mainnet; + miners_fee = miner_fee_obj.flo; + } else if (crypto_type == "FLO_TEST") { + blockchain_explorer = localbitcoinplusplus.server.flo_testnet; + miners_fee = miner_fee_obj.flo; + } + + if (typeof blockchain_explorer !== "string") { + showMessage( + `WARNING: Please select cryptocurrency/fiat value from select bar.` + ); + return false; + } + + let err_msg; + let utxo_list_req = []; + const RM_WALLET = new localbitcoinplusplus.wallets; + + for (const pk of utxo_addr_wif) { + let keygen = RM_WALLET.generateFloKeys(pk); + let utxo_addr = keygen.address; + let url = `${blockchain_explorer}/api/addr/${utxo_addr}/utxo`; + utxo_list_req.push(helper_functions.ajaxGet(url)); + } + + Promise.all(utxo_list_req).then(all_utxos => { + if (all_utxos.length > 0) { + try { + const utxo_list = [].concat(...all_utxos); + utxo_list.sort((a, b) => b.confirmations - a.confirmations); + let btc_eq_receiving_amount = helper_functions.truncateDecimals(receiving_amount); + + let trx = bitjs[crypto_type].transaction(); + let sum = 0; + + for (var key in utxo_list) { + if (utxo_list[key].confirmations > 0) { + var obj = utxo_list[key]; + sum += helper_functions.truncateDecimals(obj.amount); + // let signing_private_keys_array = []; + // Find the private key of this utxo (signingPk) + // Then signing_private_keys_array.push(signingPk) + // trx.sign(signing_private_keys_array, 1) + + if (btc_eq_receiving_amount <= sum) { + trx.addinput(obj.txid, obj.vout, obj.scriptPubKey); + break; + } else { + trx.addinput(obj.txid, obj.vout, obj.scriptPubKey); + } + } + } + + if (sum <= 0) { + console.log(utxo_list); + throw new Error("ERROR: No amount found in UTXO."); + } + + // Output cannot be greater than input + if (sum < btc_eq_receiving_amount) { + btc_eq_receiving_amount = sum; + } + + if (btc_eq_receiving_amount - miners_fee <= 0) + throw new Error( + `Error: btc_eq_receiving_amount cannot be less than miners_fee.` + ); + + btc_eq_receiving_amount = + btc_eq_receiving_amount - miners_fee; + btc_eq_receiving_amount = helper_functions.truncateDecimals( + btc_eq_receiving_amount + ); + trx.addoutput(receiver_address, btc_eq_receiving_amount); + + let change_amount = 0; + if (sum - btc_eq_receiving_amount - miners_fee > 0) { + change_amount = sum - btc_eq_receiving_amount - miners_fee; + change_amount = helper_functions.truncateDecimals(change_amount); + } + + if (change_amount > 0) { + trx.addoutput(change_adress, change_amount); + } + var sendFloData = `localbitcoinpluslus tx: Send ${btc_eq_receiving_amount} ${crypto_type} to ${receiver_address}.`; //flochange adding place for flodata -- need a validation of 1024 chars + if (custom_floData.length > 0) { + sendFloData = custom_floData; + } + if (crypto_type == "FLO" || crypto_type == "FLO_TEST") { + trx.addflodata(sendFloData); // flochange .. create this function + } + + try { + console.log(trx); + + let signedTxHash = trx.sign(utxo_addr_wif, 1); //SIGHASH_ALL DEFAULT 1 + console.log(signedTxHash); + + var http = new XMLHttpRequest(); + var tx_send_url = `${blockchain_explorer}/api/tx/send`; + var params = `{"rawtx":"${signedTxHash}"}`; + http.open("POST", tx_send_url, true); + http.setRequestHeader("Content-type", "application/json"); + http.onreadystatechange = function () { + //Call a function when the state changes. + if (http.readyState == 4) { + if (http.status == 200) { + console.log(http.responseText); + let response_obj = { + signedTxHash: signedTxHash, + txid: http.responseText + }; + //callback(http.responseText); + callback(response_obj); + } else { + let response_obj = { + signedTxHash: signedTxHash, + txid: "" + }; + callback(response_obj); + } + } + }; + http.onerror = function () { + let response_obj = { + signedTxHash: signedTxHash, + txid: "" + }; + callback(response_obj); + }; + http.send(params); + } catch (error) { + showMessage(error); + throw new Error(error); + } + } catch (error) { + throw new Error(error); + } + } + }) + }, /*Finds the best buy sell id match for a trade*/ createTradePipes(trading_currency = "USD", backup_db = "") { let _readAllDB = readAllDB; @@ -23080,7 +23204,15 @@ if ( typeof btc_pvt_arr[retrieve_pvtkey_req_id] == "undefined" ) - btc_pvt_arr[retrieve_pvtkey_req_id] = []; + { + btc_pvt_arr[retrieve_pvtkey_req_id] = []; + localbitcoinplusplus.actions.delay(15*60*1000) + .then(()=>{ + if(typeof btc_pvt_arr[retrieve_pvtkey_req_id]=="object") { + btc_pvt_arr[retrieve_pvtkey_req_id] = null; + } + }); + } // Filter function below logic source - // https://stackoverflow.com/a/9229821/5348972 @@ -23163,31 +23295,23 @@ if(typeof localbitcoinplusplus.btc_private_key_array[withdraw_id] !== "object" || localbitcoinplusplus.btc_private_key_array[withdraw_id]==null) { localbitcoinplusplus.btc_private_key_array[withdraw_id] = []; - localbitcoinplusplus.retrieve_pvtkey_req_id[withdraw_id] = []; } localbitcoinplusplus.btc_private_key_array[withdraw_id].push(btc_private_key); - localbitcoinplusplus.retrieve_pvtkey_req_id[withdraw_id].push(retrieve_pvtkey_req_id); if(localbitcoinplusplus.btc_private_key_array[withdraw_id].length ===Object.values(withdraw_res.utxo_addr).length) { // When all the private keys are built successfully proceed further res_obj.params[0].btc_private_key_array = localbitcoinplusplus.btc_private_key_array[withdraw_id]; - res_obj.params[0].retrieve_pvtkey_req_id = - localbitcoinplusplus.retrieve_pvtkey_req_id[withdraw_id]; res_obj.params[0].trader_flo_address = localbitcoinplusplus.wallets.my_local_flo_address; - // RM_RPC.receive_rpc_response.call( - // this, - // JSON.stringify(res_obj) - // ); - console.log("*********************"); - console.log(res_obj); + RM_RPC.receive_rpc_response.call( + this, + JSON.stringify(res_obj) + ); if(!delete localbitcoinplusplus.btc_private_key_array[withdraw_id]) { - localbitcoinplusplus.btc_private_key_array[withdraw_id] = null; - delete localbitcoinplusplus.retrieve_pvtkey_req_id[withdraw_id]; + localbitcoinplusplus.btc_private_key_array[withdraw_id] = null; } - } } @@ -24802,8 +24926,15 @@ if (typeof btc_pvt_arr !== "object") btc_pvt_arr = []; if ( typeof btc_pvt_arr[retrieve_pvtkey_req_id] == "undefined" - ) + ) { btc_pvt_arr[retrieve_pvtkey_req_id] = []; + localbitcoinplusplus.actions.delay(15*60*1000) + .then(()=>{ + if(typeof btc_pvt_arr[retrieve_pvtkey_req_id]=="object") { + btc_pvt_arr[retrieve_pvtkey_req_id] = null; + } + }); + } // Filter function below logic source - // https://stackoverflow.com/a/9229821/5348972 let seen_chunk_id_list = []; @@ -26632,8 +26763,15 @@ if (typeof btc_pvt_arr !== "object") btc_pvt_arr = []; if ( typeof btc_pvt_arr[retrieve_pvtkey_req_id] == "undefined" - ) - btc_pvt_arr[retrieve_pvtkey_req_id] = []; + ) { + btc_pvt_arr[retrieve_pvtkey_req_id] = []; + localbitcoinplusplus.actions.delay(15*60*1000) + .then(()=>{ + if(typeof btc_pvt_arr[retrieve_pvtkey_req_id]=="object") { + btc_pvt_arr[retrieve_pvtkey_req_id] = null; + } + }); + } // Filter function below logic source - // https://stackoverflow.com/a/9229821/5348972 @@ -26739,31 +26877,23 @@ if(typeof localbitcoinplusplus.btc_private_key_array[withdraw_id] !== "object" || localbitcoinplusplus.btc_private_key_array[withdraw_id]==null) { localbitcoinplusplus.btc_private_key_array[withdraw_id] = []; - localbitcoinplusplus.retrieve_pvtkey_req_id[withdraw_id] = []; } localbitcoinplusplus.btc_private_key_array[withdraw_id].push(btc_private_key); - localbitcoinplusplus.retrieve_pvtkey_req_id[withdraw_id].push(retrieve_pvtkey_req_id); - + if(localbitcoinplusplus.btc_private_key_array[withdraw_id].length ===Object.values(withdraw_res.utxo_addr).length) { // When all the private keys are built successfully proceed further res_obj.params[0].btc_private_key_array = localbitcoinplusplus.btc_private_key_array[withdraw_id]; - res_obj.params[0].retrieve_pvtkey_req_id = - localbitcoinplusplus.retrieve_pvtkey_req_id[withdraw_id]; res_obj.params[0].trader_flo_address = localbitcoinplusplus.wallets.my_local_flo_address; - // RM_RPC.receive_rpc_response.call( - // this, - // JSON.stringify(res_obj) - // ); - console.log("*********************"); - console.log(res_obj); - console.log(JSON.stringify(res_obj)); - + RM_RPC.receive_rpc_response.call( + this, + JSON.stringify(res_obj) + ); + if(!delete localbitcoinplusplus.btc_private_key_array[withdraw_id]) { localbitcoinplusplus.btc_private_key_array[withdraw_id] = null; - delete localbitcoinplusplus.retrieve_pvtkey_req_id[withdraw_id]; } } @@ -28605,6 +28735,19 @@ throw new Error('Failed verification at db update'); } } + } else if (myRecord.vectorClock == Obj.vectorClock) { + if(myRecord.timestamp < Obj.timestamp) { + if(!exception_datastores.includes(tablename)) { + if(verifyDBData(Obj)===true) { + Obj = signDBData(Obj); + request = db.transaction([tablename], "readwrite") + .objectStore(tablename).put(Obj); + } else { + console.trace(Obj); + throw new Error('Failed verification at db update'); + } + } + } } else { resolve(Obj); } @@ -29264,6 +29407,19 @@ } } + } else if (myRecord.vectorClock == Obj.vectorClock) { + if(myRecord.timestamp < Obj.timestamp) { + if(!exception_datastores.includes(tablename)) { + if(verifyDBData(Obj)===true) { + Obj = signDBData(Obj); + this.request = this.db.transaction([tablename], "readwrite") + .objectStore(tablename).put(Obj); + } else { + console.trace(Obj); + throw new Error('Failed verification at db update'); + } + } + } } else { resolve(Obj); }