diff --git a/index.html b/index.html index f8d2be3..6f22898 100644 --- a/index.html +++ b/index.html @@ -13896,7 +13896,6 @@ reactor.registerEvent("informLeftSuperNode"); reactor.registerEvent("informRightSuperNode"); reactor.registerEvent("message_for_user"); - reactor.registerEvent("refresh_reserved_crypto_balances"); reactor.registerEvent("remove_temp_data_from_db"); reactor.addEventListener("new_supernode_connected", async function(evt) { @@ -14651,7 +14650,8 @@ ) { // Also refresh deposited crypto balances - reactor.dispatchEvent("refresh_reserved_crypto_balances", conn_su_flo_id); + const RM_WALLET = new localbitcoinplusplus.wallets; + RM_WALLET.refresh_reserved_crypto_balances(conn_su_flo_id); // If conn_su_flo_id is not an immediate backup then give your data to it to sync const myClosestSus = await readAllDB("myClosestSupernodes"); @@ -15008,104 +15008,6 @@ } }); - reactor.addEventListener("refresh_reserved_crypto_balances", async function(user_flo_addr='') { - try { - const getSupernode = await localbitcoinplusplus.kademlia.determineClosestSupernode(user_flo_addr); - const getSupernodeAddr = getSupernode[0].data.id; - let backup_db = null; - let _readAllDB = readAllDB; - let _updateinDB = updateinDB; - let _readDBbyIndex = readDBbyIndex; - - if(getSupernodeAddr!==localbitcoinplusplus.wallets.my_local_flo_address) { - backup_db = getSupernodeAddr; - } - if (typeof backup_db == "string" && backup_db.length > 0) { - if ( - typeof localbitcoinplusplus.newBackupDatabase.db[backup_db] == - "object" - ) { - const foreign_db = - localbitcoinplusplus.newBackupDatabase.db[backup_db]; - _readAllDB = foreign_db.backup_readAllDB.bind(foreign_db); - _updateinDB = foreign_db.backup_updateinDB.bind(foreign_db); - _readDBbyIndex = foreign_db.backup_readDBbyIndex.bind(foreign_db); - } else { - if(backup_db!==localbitcoinplusplus.wallets.my_local_flo_address) { - err_msg = `WARNING: Invalid Backup DB Instance Id: ${backup_db}.`; - showMessage(err_msg); - throw new Error(err_msg); - } - } - } - - const get_crypto_deposits = await _readAllDB('deposit'); - - for (const crypto_deposits of get_crypto_deposits) { - let crypto_address = crypto_deposits.btc_address; - let explorer; - let decimal = 100000000; - let crypto_diff = localbitcoinplusplus.master_configurations.btcTradeMargin; - switch (crypto_deposits.product) { - case "BTC": - explorer = localbitcoinplusplus.server.btc_mainnet; - break; - case "BTC_TEST": - explorer = localbitcoinplusplus.server.btc_testnet; - break; - case "FLO": - explorer = localbitcoinplusplus.server.flo_mainnet; - decimal = 1; - crypto_diff = crypto_diff/decimal; - break; - case "FLO_TEST": - explorer = localbitcoinplusplus.server.flo_testnet; - decimal = 1; - crypto_diff = crypto_diff/decimal; - break; - default: - break; - } - - let url = `${explorer}/api/addr/${crypto_address}/balance`; - console.log(url); - let balance = await helper_functions.ajaxGet(url); - if (!isNaN(balance) && parseFloat(balance) >= 0) { - balance = helper_functions.truncateDecimals(balance / decimal); - console.log(balance); - crypto_deposits.bitcoinToBePaid = balance; - - if(crypto_deposits.status!==1) { - // Do not update status for status=1 - crypto_deposits.status = 2; - } - let p1 = _updateinDB('deposit', crypto_deposits); - let p2 = Promise.resolve(true); - const reserved_pk = await _readDBbyIndex('system_btc_reserves_private_keys', 'btc_address', crypto_address) - if(typeof reserved_pk=="object" && reserved_pk.length>0) { - reserved_pk[0].balance = balance; - p2 = _updateinDB('system_btc_reserves_private_keys', reserved_pk[0], reserved_pk[0].id); - } - - Promise.all([p1,p2]) - .then(res=>{ - let timenow = + new Date(); - localStorage.setItem(`refresh_reserved_cryptos_prices_time_${getSupernodeAddr}`, timenow); - console.info('Updated reserved crypto prices.'); - }) - .catch(e=>console.warn("Failed to update balance of "+crypto_address)); - - } else { - console.warn("Failed to update balance of "+crypto_address); - } - - } - - } catch (error) { - throw new Error(error) - } - }) - reactor.addEventListener("remove_temp_data_from_db", async function() { let backup_db = null; @@ -15703,7 +15605,111 @@ .filter(f => f[1] == flo_id); return su_arr[0]; - } + }, + refresh_reserved_crypto_balances:async (user_flo_addr='', deposited_btc_array=[])=> { + try { + const getSupernode = await localbitcoinplusplus.kademlia.determineClosestSupernode(user_flo_addr); + const getSupernodeAddr = getSupernode[0].data.id; + let backup_db = null; + let _readAllDB = readAllDB; + let _updateinDB = updateinDB; + let _readDBbyIndex = readDBbyIndex; + + if(getSupernodeAddr!==localbitcoinplusplus.wallets.my_local_flo_address) { + backup_db = getSupernodeAddr; + } + if (typeof backup_db == "string" && backup_db.length > 0) { + if ( + typeof localbitcoinplusplus.newBackupDatabase.db[backup_db] == + "object" + ) { + const foreign_db = + localbitcoinplusplus.newBackupDatabase.db[backup_db]; + _readAllDB = foreign_db.backup_readAllDB.bind(foreign_db); + _updateinDB = foreign_db.backup_updateinDB.bind(foreign_db); + _readDBbyIndex = foreign_db.backup_readDBbyIndex.bind(foreign_db); + } else { + if(backup_db!==localbitcoinplusplus.wallets.my_local_flo_address) { + err_msg = `WARNING: Invalid Backup DB Instance Id: ${backup_db}.`; + showMessage(err_msg); + throw new Error(err_msg); + } + } + } + + let get_crypto_deposits = []; + if(deposited_btc_array.length<=0) { + let all_deposits = await _readAllDB('deposit'); + get_crypto_deposits = all_deposits.map(m=>m.btc_address) + } else { + for (const thisdeposit of deposited_btc_array) { + let depo_obj = await _readDBbyIndex('deposit', 'btc_address', thisdeposit); + if(typeof depo_obj[0].btc_address !== "string") continue; + get_crypto_deposits.push(depo_obj[0]); + } + } + + let deposit_promises = []; + + for (const crypto_deposits of get_crypto_deposits) { + let crypto_address = crypto_deposits.btc_address; + let explorer; + let decimal = 100000000; + let crypto_diff = localbitcoinplusplus.master_configurations.btcTradeMargin; + switch (crypto_deposits.product) { + case "BTC": + explorer = localbitcoinplusplus.server.btc_mainnet; + break; + case "BTC_TEST": + explorer = localbitcoinplusplus.server.btc_testnet; + break; + case "FLO": + explorer = localbitcoinplusplus.server.flo_mainnet; + decimal = 1; + crypto_diff = crypto_diff/decimal; + break; + case "FLO_TEST": + explorer = localbitcoinplusplus.server.flo_testnet; + decimal = 1; + crypto_diff = crypto_diff/decimal; + break; + default: + break; + } + + let url = `${explorer}/api/addr/${crypto_address}/balance`; + console.log(url); + let balance = await helper_functions.ajaxGet(url); + if (!isNaN(balance) && parseFloat(balance) >= 0) { + balance = helper_functions.truncateDecimals(balance / decimal); + console.log(balance); + crypto_deposits.bitcoinToBePaid = balance; + + if(crypto_deposits.status!==1) { + // Do not update status for status=1 + crypto_deposits.status = 2; + } + deposit_promises.push(_updateinDB('deposit', crypto_deposits)) + + } else { + console.warn("Failed to update balance of "+crypto_address); + } + + } + + Promise.all(deposit_promises).then(res=>{ + console.log(res); + let timenow = + new Date(); + localStorage.setItem(`refresh_reserved_cryptos_prices_time_${getSupernodeAddr}`, timenow); + console.info('Updated deposited crypto prices.'); + return res; + }) + .catch(e=>console.warn("Failed to update deposited crypto balances")); + + } catch (error) { + throw new Error(error) + } + }, }; @@ -16043,7 +16049,8 @@ if(last_updated==null || (today - last_updated > (24 * 60 * 60 * 1000))) { - reactor.dispatchEvent("refresh_reserved_crypto_balances", params.trader_flo_address); + const RM_WALLET = new localbitcoinplusplus.wallets; + RM_WALLET.refresh_reserved_crypto_balances(params.trader_flo_address); } }); @@ -16161,8 +16168,6 @@ this, ...request.params, function(supernode_signed_res) { - // supernode_signed_res.receiver_flo_address = - // params.trader_flo_address; if (typeof supernode_signed_res == "object") { RM_RPC.send_rpc .call( @@ -16671,8 +16676,7 @@ if ( trade_margin.remaining_crypto_credit < 0 || eqBTC <= 0 || - trade_margin.remaining_crypto_credit < - eqBTC + trade_margin.remaining_crypto_credit < eqBTC ) { err_msg = `Insufficient crypto balance to withdraw. You can withdraw upto: ${params.product} ${trade_margin.remaining_crypto_credit}`; err_response = { @@ -16765,8 +16769,6 @@ receivingBTC: eqBTC, currency: params.currency, product: params.product, - change_adress: - deposit_arr.btc_address, timestamp: +new Date() }; @@ -16780,24 +16782,25 @@ }); // doSend btc_private_key_shamirs_id from system_btc_reserves_private_keys - Object.values(deposited_utxo_addr_list) - .map(async vbl => { - const res = await readDBbyIndex( - "system_btc_reserves_private_keys", - "btc_address", - vbl - ); - if(typeof res!=="object" || typeof res[0].id!=="string") { - deposit_arr.status = 2; - await updateinDB( - "deposit", - deposit_arr, - deposit_arr.id, - false, - false + for (const depositedutxoaddr in deposited_utxo_addr_list) { + if (deposited_utxo_addr_list.hasOwnProperty(depositedutxoaddr)) { + const vbl = deposited_utxo_addr_list[depositedutxoaddr]; + const res = await readDBbyIndex( + "system_btc_reserves_private_keys", + "btc_address", + vbl ); - return; - } + if(typeof res!=="object" || typeof res[0].id!=="string") { + deposit_arr.status = 2; + await updateinDB( + "deposit", + deposit_arr, + deposit_arr.id, + false, + false + ); + return; + } let retrieve_pvtkey_req_id = res[0].id; res[0].btc_private_key_shamirs_id.map( bpks => { @@ -16815,10 +16818,9 @@ .then(retrieve_pvtkey_req => doSend(retrieve_pvtkey_req) ); - } - ); - - }); + }); + } + } } else { deposited_utxo_addr_list[idx]=deposit_arr.btc_address; @@ -17266,8 +17268,9 @@ // tx than to after because fetching balance after can return older or newer balance // on random events let current_utxos_balance = 0; - const RM_WALLET = new localbitcoinplusplus.wallets; + //const RM_WALLET = new localbitcoinplusplus.wallets; let total_balance_promises = []; + // Send change to the first utxo 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`; @@ -17319,7 +17322,7 @@ params.btc_private_key_array, withdraw_res.receiverBTCAddress, totalWithdrawingAmount, - withdraw_res.change_adress, + withdraw_res.utxo_addr[0], async function (res) { console.log(res); try { @@ -17368,105 +17371,57 @@ doSend(updateUserCryptoBalanceRequestObject) ); - // Check if there's BTC left in deposited BTC. If yes update its status to 2 else delete it + // Validate txid + let withdrawTxCounter=1; + (async function validateWithdrawTxidInBlockchain() { + await localbitcoinplusplus.actions.delay(180000); + const validate_withdraw_txid = await helper_functions + .ajaxGet(`${explorer}/api/tx/${res.txid}`); + console.log(validate_withdraw_txid); + if(typeof validate_withdraw_txid=="object" + && validate_withdraw_txid.txid===res.txid + && validate_withdraw_txid.confirmations>0) { - /*********************************************************************************************************************************** - *******************CHECK ACTUAL BTC BALANCE HERE THROUGH AN API AND UPDATE DEPOSIT TABLE**************************************************** - ************************************************************************************************************************************/ + const deposited_utxos_latest_status = + await RM_WALLET.refresh_reserved_crypto_balances( + withdraw_res.trader_flo_address, + withdraw_res.utxo_addr + ); - for (const deposited_utxo_idx in withdraw_res.utxo_addr) { - let deposited_utxo_addr = withdraw_res.utxo_addr[deposited_utxo_idx]; + // Send the resp to backups + RM_RPC.send_rpc( + "update_deposited_crypto_instance", + { + deposit_data: deposited_utxos_latest_status, + db_inst: params.db_inst, + trader_flo_address: + withdraw_res.trader_flo_address + } + ).then(delRequestObject => + doSend(delRequestObject) + ); - const deposit_arr_resp = await readDBbyIndex( - "deposit", - "btc_address", - deposited_utxo_addr - ); - if (typeof deposit_arr_resp[0] == "object") { - 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 - ); - } + removeinDB("withdraw_btc", withdraw_id); - if ( - typeof current_utxos_balance == "number" - ) { - deposit_arr.bitcoinToBePaid = current_utxos_balance - totalWithdrawingAmount; - } else { - throw new Error('current_utxos_balance is not a number'); - } + RM_RPC.send_rpc( + "delete_deposited_crypto_instance", + { + withdraw_btc_id: withdraw_id, + db_inst: params.db_inst, + trader_flo_address: + withdraw_res.trader_flo_address + } + ).then(delRequestObject => + doSend(delRequestObject) + ); - 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 if(n<=20) { + validateWithdrawTxidInBlockchain(); + withdrawTxCounter++; + } else { + throw new Error(`Txid ${res.txid} not registered in ${withdraw_res.product} Blockhain`); } - } + })(); } else { console.log(res); @@ -17781,7 +17736,8 @@ if(last_updated==null || (today - last_updated > (24 * 60 * 60 * 1000))) { limit_function_calls(async function() { - await reactor.dispatchEvent("refresh_reserved_crypto_balances", params.trader_flo_address); + const RM_WALLET = new localbitcoinplusplus.wallets; + RM_WALLET.refresh_reserved_crypto_balances(params.trader_flo_address); }, 600000); } }); @@ -18438,7 +18394,8 @@ reactor.dispatchEvent('message_for_user', err_response); throw new Error(err_msg); } - } else { + } else if(localbitcoinplusplus.master_configurations.tradableAsset2.includes( + params.product)) { if ( trade_margin.remaining_fiat_credit < 0 || params.withdrawing_amount <= 0 || @@ -18453,7 +18410,7 @@ reactor.dispatchEvent('message_for_user', err_response); throw new Error(err_msg); } - } + } else return; params.id = helper_functions.unique_id(); params.status = 1; @@ -18462,168 +18419,197 @@ params.product ) ) { - // Check how much cryptos the user can withdraw - const withdrawer_btc_id = `${params.trader_flo_address}_${params.product}`; - backup_server_db_instance - .backup_readDB("crypto_balances", withdrawer_btc_id) - .then(async function(btc_balance_res) { - if ( - typeof btc_balance_res == "object" && - typeof btc_balance_res.trader_flo_address == - "string" && - btc_balance_res.crypto_balance > 0 - ) { - let withdrawer_btc_balance = helper_functions.truncateDecimals( - btc_balance_res.crypto_balance - ); - const eqBTC = helper_functions.truncateDecimals(params.withdrawing_amount); + try { - let withdrawer_new_btc_balance = - withdrawer_btc_balance - eqBTC; + const eqBTC = helper_functions.truncateDecimals(params.withdrawing_amount); + if ( - withdrawer_new_btc_balance >= 0 && - withdrawer_btc_balance > 0 && - eqBTC > 0 && - eqBTC <= withdrawer_btc_balance + trade_margin.remaining_crypto_credit < 0 || + eqBTC <= 0 || + trade_margin.remaining_crypto_credit < + eqBTC ) { - // Now details of Bitcoins can be sent to withdrawer - let sum_total_btc = 0; - let valid_utxo_list = []; - let receiverBTCAddress = params.receivinAddress.trim(); - - backup_server_db_instance - .backup_readAllDB("deposit") - .then(function(deposit_list) { - if ( - typeof deposit_list == "object" && - deposit_list.length > 0 - ) { - deposit_list = deposit_list.filter( - deposits => - deposits.status == 2 && - localbitcoinplusplus.master_configurations.tradableAsset1.includes( - deposits.product - ) && - params.product == deposits.product - ); - for (const dl in deposit_list) { - if (deposit_list.hasOwnProperty(dl)) { - const deposit_dl = deposit_list[dl]; - sum_total_btc += helper_functions.truncateDecimals( - deposit_dl.bitcoinToBePaid - ); - - if (eqBTC <= sum_total_btc) { - valid_utxo_list.push(deposit_dl); - break; - } else { - valid_utxo_list.push(deposit_dl); - } - } - } - let valid_btc_list = valid_utxo_list.map( - deposit_arr => { - // Deposited Bitcoin is under process - deposit_arr.status = 3; - backup_server_db_instance.backup_updateinDB( - "deposit", - deposit_arr, - deposit_arr.id - ); - - // save the address and id in a table - const withdraw_id = helper_functions.unique_id(); - const withdraw_btc_order_object = { - id: withdraw_id, - trader_flo_address: - params.trader_flo_address, - utxo_addr: deposit_arr.btc_address, - receiverBTCAddress: - params.receivinAddress, - receivingBTC: eqBTC, - currency: params.currency, - product: params.product, - change_adress: - deposit_arr.btc_address, - timestamp: +new Date() - }; - backup_server_db_instance.backup_addDB( - "withdraw_btc", - withdraw_btc_order_object - ); - let withdraw_order_life = JSON.parse(localbitcoinplusplus.master_configurations.ordersLife); - localbitcoinplusplus.actions.delay(withdraw_order_life.cryptoWithdraw) - .then(()=>backup_server_db_instance - .backup_removeinDB("withdraw_btc", withdraw_id)); - return { - withdraw_id: withdraw_id, - deposited_btc_address: - deposit_arr.btc_address - }; - } - ); - - // doSend btc_private_key_shamirs_id from system_btc_reserves_private_keys - valid_btc_list.map(vbl => { - backup_server_db_instance - .backup_readDBbyIndex( - "system_btc_reserves_private_keys", - "btc_address", - vbl - ).then(async function(res) { - if(typeof res!=="object" || typeof res[0].id!=="string") { - deposit_arr.status = 2; - await backup_server_db_instance - .backup_updateinDB( - "deposit", - deposit_arr, - deposit_arr.id - ); - return; - } - let retrieve_pvtkey_req_id = - res[0].id; - res[0].btc_private_key_shamirs_id.map( - bpks => { - RM_RPC.send_rpc - .call( - this, - "send_back_shamirs_secret_btc_pvtkey", - { - retrieve_pvtkey_req_id: retrieve_pvtkey_req_id, - chunk_val: bpks, - withdraw_id: withdraw_id, - db_inst: primarySupernodeForThisUser - } - ) - .then(retrieve_pvtkey_req => - doSend(retrieve_pvtkey_req) - ); - } - ); - }); - }); - } - }); - } else { - err_msg = `Withdrawal request failed: You are trying to withdraw more ${params.product} than you have.`; - err_response = { - user_flo_addr: params.trader_flo_address, - msg: err_msg - } - reactor.dispatchEvent('message_for_user', err_response); - throw new Error(err_msg); + err_msg = `Insufficient crypto balance to withdraw. You can withdraw upto: ${params.product} ${trade_margin.remaining_crypto_credit}`; + err_response = { + user_flo_addr: params.trader_flo_address, + msg: err_msg + } + reactor.dispatchEvent('message_for_user', err_response); + throw new Error(err_msg); } - } else { - err_msg = `Withdrawal request failed: You don't seem to have any ${params.product} balance in the system yet. - Please buy some Bitcoins to withdraw.`; - err_response = { - user_flo_addr: params.trader_flo_address, - msg: err_msg - } - reactor.dispatchEvent('message_for_user', err_response); + + // Check how much cryptos the user can withdraw + let withdrawer_btc_id = `${params.trader_flo_address}_${params.product}`; + backup_server_db_instance + .backup_readDB("crypto_balances", withdrawer_btc_id).then( + async function(btc_balance_res) { + if ( + typeof btc_balance_res == "object" && + typeof btc_balance_res.trader_flo_address == + "string" && + btc_balance_res.crypto_balance > 0 + ) { + let withdrawer_btc_balance = helper_functions.truncateDecimals( + btc_balance_res.crypto_balance + ); + + let withdrawer_new_btc_balance = + withdrawer_btc_balance - eqBTC; + if ( + withdrawer_new_btc_balance >= 0 && + withdrawer_btc_balance > 0 && + eqBTC > 0 && + eqBTC <= withdrawer_btc_balance + ) { + // Now details of Bitcoins can be sent to withdrawer + + let sum_total_btc = 0; + let valid_utxo_list = []; + let receiverBTCAddress = params.receivinAddress.trim(); + + const deposit_list = await backup_server_db_instance + .backup_readAllDB("deposit"); + if ( + typeof deposit_list == "object" && + deposit_list.length > 0 + ) { + + for (const dl in deposit_list) { + if (deposit_list.hasOwnProperty(dl)) { + const deposit_dl = deposit_list[dl]; + if(( + deposit_dl.status == 2 && + localbitcoinplusplus.master_configurations.tradableAsset1.includes( + deposit_dl.product + ) && + params.product == deposit_dl.product + )) { + // Deposited Bitcoin is under process + deposit_dl.status = 3; + await backup_server_db_instance + .backup_updateinDB( + "deposit", + deposit_dl, + deposit_dl.id + ); + sum_total_btc += helper_functions.truncateDecimals( + deposit_dl.bitcoinToBePaid + ); + + if (eqBTC <= sum_total_btc) { + valid_utxo_list.push(deposit_dl); + break; + } else { + valid_utxo_list.push(deposit_dl); + } + } + } + } + let deposited_utxo_addr_list = {}; + let idx = 0; + for (const deposit_arr of valid_utxo_list) { + + if(idx==valid_utxo_list.length-1) { + deposited_utxo_addr_list[idx]=deposit_arr.btc_address; + // save the address and id in a table + let withdraw_id = helper_functions.unique_id(); + const withdraw_btc_order_object = { + id: withdraw_id, + trader_flo_address: + params.trader_flo_address, + utxo_addr: deposited_utxo_addr_list, + receiverBTCAddress: + params.receivinAddress, + receivingBTC: eqBTC, + currency: params.currency, + product: params.product, + timestamp: +new Date() + }; + + await backup_server_db_instance + .backup_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); + localbitcoinplusplus.actions.delay(withdraw_order_life.cryptoWithdraw) + .then(()=>{ + backup_server_db_instance + .backup_removeinDB("withdraw_btc", withdraw_id) + }); + + // doSend btc_private_key_shamirs_id from system_btc_reserves_private_keys + for (const depositedutxoaddr in deposited_utxo_addr_list) { + if (deposited_utxo_addr_list.hasOwnProperty(depositedutxoaddr)) { + const vbl = deposited_utxo_addr_list[depositedutxoaddr]; + const res = await backup_server_db_instance + .backup_readDBbyIndex( + "system_btc_reserves_private_keys", + "btc_address", + vbl + ); + if(typeof res!=="object" || typeof res[0].id!=="string") { + deposit_arr.status = 2; + await backup_server_db_instance + .backup_updateinDB( + "deposit", + deposit_arr, + deposit_arr.id, + false, + false + ); + return; + } + let retrieve_pvtkey_req_id = res[0].id; + res[0].btc_private_key_shamirs_id.map( + bpks => { + RM_RPC.send_rpc + .call( + this, + "send_back_shamirs_secret_btc_pvtkey", + { + retrieve_pvtkey_req_id: retrieve_pvtkey_req_id, + chunk_val: bpks, + withdraw_id: withdraw_id, + db_inst: primarySupernodeForThisUser + } + ) + .then(retrieve_pvtkey_req => + doSend(retrieve_pvtkey_req) + ); + }); + } + } + + } else { + deposited_utxo_addr_list[idx]=deposit_arr.btc_address; + } + idx++; + } + } + + } else { + err_msg = `Withdrawal request failed: You are trying to withdraw more ${params.product} than you have.`; + err_response = { + user_flo_addr: params.trader_flo_address, + msg: err_msg + } + reactor.dispatchEvent('message_for_user', err_response); + throw new Error(err_msg); + } + } else { + err_msg = `Withdrawal request failed: You don't seem to have any ${params.product} balance in the system yet. + Please buy some ${params.product} to withdraw.`; + err_response = { + user_flo_addr: params.trader_flo_address, + msg: err_msg + } + reactor.dispatchEvent('message_for_user', err_response); + } + }); + + } catch (error) { + console.log(error); } - }); } else if ( localbitcoinplusplus.master_configurations.tradableAsset2.includes( params.product @@ -18997,60 +18983,45 @@ RM_RPC.filter_legit_backup_requests( params.trader_flo_address, async function (is_valid_request) { - if (is_valid_request !== true) return false; - - if ( - typeof params.btc_private_key_array !== "string" || - typeof params.retrieve_pvtkey_req_id !== "string" - ) - 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; - - backup_server_db_instance = - localbitcoinplusplus.newBackupDatabase.db[params.db_inst]; - - if (typeof backup_server_db_instance !== "object") return; - - let btc_private_key_str = params.btc_private_key_array; - let retrieve_pvtkey_req_id = params.retrieve_pvtkey_req_id; - let withdraw_id = params.withdraw_id; - try { - let btc_private_key_object = JSON.parse( - btc_private_key_str - ); - 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; + + backup_server_db_instance = + localbitcoinplusplus.newBackupDatabase.db[params.db_inst]; + + if (typeof backup_server_db_instance !== "object") return; + + const withdraw_id = params.withdraw_id; const withdraw_res = await backup_server_db_instance .backup_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 backup_server_db_instance .backup_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") { @@ -19098,372 +19069,249 @@ 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 backup_server_db_instance - .backup_readDB("system_btc_reserves_private_keys", retrieve_pvtkey_req_id); + const totalWithdrawingAmount = helper_functions.truncateDecimals(withdraw_res.receivingBTC); - 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); - - 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_pk_shares_array); - console.log(transaction_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 backup_server_db_instance.backup_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.utxo_addr[0], + 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) + ); - let withdrawer_crypto_bal_id = `${withdraw_res.trader_flo_address}_${withdraw_res.product}`; + 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 + ); - 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 backup_server_db_instance - .backup_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 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) + ); + + // Validate txid + let withdrawTxCounter=1; + (async function validateWithdrawTxidInBlockchain() { + await localbitcoinplusplus.actions.delay(180000); + const validate_withdraw_txid = await helper_functions + .ajaxGet(`${explorer}/api/tx/${res.txid}`); + console.log(validate_withdraw_txid); + if(typeof validate_withdraw_txid=="object" + && validate_withdraw_txid.txid===res.txid + && validate_withdraw_txid.confirmations>0) { + + const deposited_utxos_latest_status = + await RM_WALLET.refresh_reserved_crypto_balances( + withdraw_res.trader_flo_address, + withdraw_res.utxo_addr ); - const updateUserCryptoBalanceObject = { - updatedBTCBalanceObject: updated_crypto_balance, - updatedBTCBalanceObjectSign: res_obj_sign, - trader_flo_address: - withdraw_res.trader_flo_address, - receiver_flo_address: + // Send the resp to backups + RM_RPC.send_rpc( + "update_deposited_crypto_instance", + { + deposit_data: deposited_utxos_latest_status, + db_inst: params.db_inst, + trader_flo_address: withdraw_res.trader_flo_address - }; + } + ).then(delRequestObject => + doSend(delRequestObject) + ); + + backup_server_db_instance + .backup_removeinDB("withdraw_btc", withdraw_id); RM_RPC.send_rpc( - "updateUserCryptoBalanceRequest", - updateUserCryptoBalanceObject - ).then( - updateUserCryptoBalanceRequestObject => - doSend( - updateUserCryptoBalanceRequestObject - ) + "delete_deposited_crypto_instance", + { + withdraw_btc_id: withdraw_id, + db_inst: params.db_inst, + trader_flo_address: + withdraw_res.trader_flo_address + } + ).then(delRequestObject => + doSend(delRequestObject) ); - // 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**************************************************** - ************************************************************************************************************************************/ - - const deposit_arr_resp = await backup_server_db_instance - .backup_readDBbyIndex( - "deposit", - "btc_address", - withdraw_res.utxo_addr - ); - if ( - typeof deposit_arr_resp == - "object" - ) { - const deposit_arr = deposit_arr_resp[0]; - if ( - !isNaN(current_balance) && - parseFloat( - current_balance - ) > 0 - ) { - current_balance = helper_functions.truncateDecimals( - current_balance / decimal - ); - } - - 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 backup_server_db_instance.backup_updateinDB( - "deposit", - deposit_arr, - deposit_arr.id - ); - - // Update new balance in system_btc_reserves - const reserves_resp = await backup_server_db_instance.backup_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) - ); - - await localbitcoinplusplus.actions.delay(180000); - - await backup_server_db_instance.backup_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 - ) - ); - - } else { - await localbitcoinplusplus.actions.delay(180000) - - // delete entry in deposits in db - let p1 = backup_server_db_instance.backup_removeinDB( - "deposit", - deposit_arr.id - ); - - let p2 = backup_server_db_instance.backup_removeinDB( - "system_btc_reserves_private_keys", - retrieve_pvtkey_req_id - ); - - let p3 = backup_server_db_instance.backup_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 if(n<=20) { + validateWithdrawTxidInBlockchain(); + withdrawTxCounter++; } else { - console.log(res); - throw new Errror( - `ERROR: Failed to make transaction.` - ); - return false; + throw new Error(`Txid ${res.txid} not registered in ${withdraw_res.product} Blockhain`); } + })(); + return true; - } catch (error) { - console.warn(error); - err_response = { - user_flo_addr: params.trader_flo_address, - msg: `Withdraw crypto request failed. Please try again later.` - } - reactor.dispatchEvent('message_for_user', err_response); + } 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.`); + } - // Do not delete these data instantly as the data - // may be required by a follow-up withdraw request - await localbitcoinplusplus.actions.delay(180000); + } 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); - await backup_server_db_instance - .backup_removeinDB("withdraw_btc", withdraw_id); - // update deposits status back to 2 in db - const deposit_arr_resp = await backup_server_db_instance - .backup_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 - backup_server_db_instance - .backup_updateinDB( - "deposit", - deposit_arr_resp[0], - deposit_arr_resp[0].id - ); - } - - } + // 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 backup_server_db_instance + .backup_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 backup_server_db_instance + .backup_updateinDB( + "deposit", + deposit_arr_resp[0], + deposit_arr_resp[0].id + ); } } - ); - } - } + await backup_server_db_instance + .backup_removeinDB("withdraw_btc", withdraw_id); + } + } + ); } } catch (error) { - + const withdraw_res = await backup_server_db_instance - .backup_readDB("withdraw_btc", withdraw_id); - // update deposits status back to 2 in db - const deposit_arr_resp = await backup_server_db_instance - .backup_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 backup_server_db_instance - .backup_updateinDB( + .backup_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 backup_server_db_instance + .backup_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 + backup_server_db_instance + .backup_updateinDB( + "deposit", + deposit_arr_resp[0], + deposit_arr_resp[0].id + ); + } } - await backup_server_db_instance - .backup_removeinDB("withdraw_btc", withdraw_id); + backup_server_db_instance + .backup_removeinDB("withdraw_btc", params.withdraw_id); + // Revert user balance + backup_server_db_instance + .backup_updateinDB("crypto_balances", + withdrawer_crypto_bal_response_before_update, + withdrawer_crypto_bal_response_before_update.id, + false, + false + ); + throw new Error(error); } } - ) - - break; + ); + break; case "superNodeSignedAddUserPublicData": if ( @@ -20917,11 +20765,9 @@ `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 - ); + btc_eq_receiving_amount - miners_fee); + trx.addoutput(receiver_address, btc_eq_receiving_amount); let change_amount = 0; @@ -22332,7 +22178,8 @@ let remove_promises_res = await Promise.all(remove_promises); console.log(remove_promises_res); // Also refresh deposited crypto balances - reactor.dispatchEvent("refresh_reserved_crypto_balances", + const RM_WALLET = new localbitcoinplusplus.wallets; + RM_WALLET.refresh_reserved_crypto_balances( localbitcoinplusplus.wallets.my_local_flo_address); } @@ -22612,9 +22459,6 @@ if ( typeof res_obj.globalParams.primarySupernode !== "string" ) { - showMessage( - `INFO: You are not authorized to serve this request.` - ); return false; } } @@ -24911,88 +24755,152 @@ } break; case "retrieve_shamirs_secret_btc_pvtkey": - if ( + if ( typeof res_obj.params == "object" && typeof res_obj.params[0] == "object" && typeof res_obj.params[0].private_key_chunk == "object" && typeof res_obj.params[0].retrieve_pvtkey_req_id == - "string" && + "string" && typeof res_obj.params[0].withdraw_id == "string" && typeof res_obj.params[0].db_inst == "string" && typeof localbitcoinplusplus.wallets.my_local_flo_address == - "string" && + "string" && res_obj.params[0].receiver_flo_address === - localbitcoinplusplus.wallets.my_local_flo_address - ) { + localbitcoinplusplus.wallets.my_local_flo_address + ) { // This message was for Primary Supernode and is meant to be run in onMessage() - if ( - res_obj.params[0].db_inst == - localbitcoinplusplus.wallets.my_local_flo_address - ) - return; + if (res_obj.params[0].db_inst == + localbitcoinplusplus.wallets.my_local_flo_address + ) return; let shamirs_shares_response = res_obj.params[0]; let retrieve_pvtkey_req_id = - res_obj.params[0].retrieve_pvtkey_req_id; + res_obj.params[0].retrieve_pvtkey_req_id; let withdraw_id = res_obj.params[0].withdraw_id; 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") { + 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 = []; btc_pvt_arr[retrieve_pvtkey_req_id].filter(function(item) { - if (typeof item.private_key_chunk !== "undefined") { - return seen_chunk_id_list.hasOwnProperty( - item.private_key_chunk.id - ) - ? false - : seen_chunk_id_list.push(item.private_key_chunk.id); + if(typeof item.private_key_chunk=="object" && + typeof item.private_key_chunk.id=="string" && + !seen_chunk_id_list.hasOwnProperty( + item.private_key_chunk.id + ) ) { + return seen_chunk_id_list.push(item.private_key_chunk.id); } }); if ( - !seen_chunk_id_list.includes( + !seen_chunk_id_list.includes( shamirs_shares_response.private_key_chunk.id - ) && - typeof shamirs_shares_response.private_key_chunk.id == + ) && + typeof shamirs_shares_response.private_key_chunk.id == "string" ) { - btc_pvt_arr[retrieve_pvtkey_req_id].push( + btc_pvt_arr[retrieve_pvtkey_req_id].push( shamirs_shares_response - ); + ); } if ( - btc_pvt_arr[retrieve_pvtkey_req_id].length === - localbitcoinplusplus.master_configurations + btc_pvt_arr[retrieve_pvtkey_req_id].length === + localbitcoinplusplus.master_configurations .ShamirsMaxShares ) { - delete res_obj.params[0].private_key_chunk; - res_obj.params[0].btc_private_key_array = JSON.stringify( - btc_pvt_arr[retrieve_pvtkey_req_id] - ); - res_obj.params[0].trader_flo_address = - localbitcoinplusplus.wallets.my_local_flo_address; - RM_RPC.backup_receive_rpc_response.call( - this, - JSON.stringify(res_obj) - ); + const backup_server_db_instance = + localbitcoinplusplus.newBackupDatabase.db[primarySupernodeOfThisUser]; - localbitcoinplusplus.actions.delay(300000).then(() => { - btc_pvt_arr[retrieve_pvtkey_req_id] = []; // Unset the object - }); + if (typeof backup_server_db_instance !== "object") { + let backup_db_error_msg = `WARNING: Unknown DB instance. DB Backup failed.`; + throw new Error(backup_db_error_msg); } - } + delete res_obj.params[0].private_key_chunk; + let btc_pk_shares_array = btc_pvt_arr[retrieve_pvtkey_req_id] + .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); + const btc_reserves = await backup_server_db_instance + .backup_readDB("system_btc_reserves_private_keys", retrieve_pvtkey_req_id); + if (typeof btc_reserves !== "object") { + console.warn(`Record for ${retrieve_pvtkey_req_id} not found in system_btc_reserves_private_keys`); + break; + } + + 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) { + console.warn(`Failed to build tx key for ${retrieve_pvtkey_req_id} in system_btc_reserves_private_keys`); + break; + } + let btc_private_key = RM_WALLET.rebuild_private_key( + btc_pk_shares_array, + transaction_key + ); + if (btc_private_key.length <= 0) { + console.warn(`Failed to build private key for ${retrieve_pvtkey_req_id} in system_btc_reserves_private_keys`); + break; + } + console.log(btc_private_key); + + const withdraw_res = await backup_server_db_instance + .backup_readDB("withdraw_btc", withdraw_id); + if(typeof withdraw_res=="object" + && typeof withdraw_res.utxo_addr=="object") { + const RM_WALLET = new localbitcoinplusplus.wallets; + let crypto_addr_gen = RM_WALLET.generateFloKeys(btc_private_key, withdraw_res.product); + let crypto_addr = crypto_addr_gen.address; + if(!Object.values(withdraw_res.utxo_addr).includes(crypto_addr)) { + console.warn(`${crypto_addr} deposit address not present in withdraw id ${withdraw_id}`); + break; + } + + if(typeof localbitcoinplusplus.btc_private_key_array!=="object" + || Object.keys(localbitcoinplusplus.btc_private_key_array).length==0) { + localbitcoinplusplus.btc_private_key_array={}; + } + 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.btc_private_key_array[withdraw_id].push(btc_private_key); + + 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].trader_flo_address = localbitcoinplusplus.wallets.my_local_flo_address; + RM_RPC.backup_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; + } + } + + } + btc_pvt_arr = Object.keys(btc_pvt_arr).filter(f=>f!==retrieve_pvtkey_req_id); + } + } break; case "update_all_new_cash_withdraw_recorded_in_db": @@ -25709,22 +25617,18 @@ ); } - if (typeof res_data.deposit_data == "object") - _updateinDB( - "deposit", - res_data.deposit_data, - res_data.deposit_data.id, - true, - false - ); - if (typeof res_data.btc_reserve_data == "object") - _updateinDB( - "system_btc_reserves_private_keys", - res_data.btc_reserve_data, - res_data.btc_reserve_data.id.id, - true, - false - ); + if (typeof res_data.deposit_data == "object") { + for (const deposits of res_data.deposit_data) { + _updateinDB( + "deposit", + deposits, + deposits.id, + true, + false + ); + } + } + } } catch (e) { console.error(e); @@ -27627,22 +27531,17 @@ ); } - if (typeof res_data.deposit_data == "object") - _updateinDB( - "deposit", - res_data.deposit_data, - res_data.deposit_data.id, - true, - false - ); - if (typeof res_data.btc_reserve_data == "object") - _updateinDB( - "system_btc_reserves_private_keys", - res_data.btc_reserve_data, - res_data.btc_reserve_data.id.id, - true, - false - ); + if (typeof res_data.deposit_data == "object") { + for (const deposits of res_data.deposit_data) { + _updateinDB( + "deposit", + deposits, + deposits.id, + true, + false + ); + } + } } } catch (e) { console.error(e); @@ -29445,7 +29344,9 @@ }.bind(this); } else { if(!exception_datastores.includes(tablename)) { - Obj = signDBData(Obj); + if(verifyDBData(Obj)===true) { + Obj = signDBData(Obj); + } } this.request = this.db.transaction([tablename], "readwrite") .objectStore(tablename).put(Obj);