/**
  * example.com/api/<guid>/sendmany?to=xxx&amount=satoshis&note=yyy&password=zzz&account=invoice&debug=1
  */
 public function sendmany($guid)
 {
     // because it can be a long process, set execution time to a lot more
     ini_set('max_execution_time', 600);
     ini_set('memory_limit', '512M');
     if (!$this->attemptAuth()) {
         return Response::json(['error' => AUTHENTICATION_FAIL]);
     }
     $recipients_json = Input::get('recipients');
     //		$note       = Input::get( 'note' );
     $note = '';
     $external_user_id = Input::get('external_user_id', null);
     $account = Input::get('account', "");
     if (!$note) {
         $note = '';
     }
     /* validate that recipients is JSON object with address:satoshi pairs */
     $recipients = json_decode($recipients_json);
     $is_valid_recipients = $this->validateSendManyJson($recipients);
     if (!$is_valid_recipients) {
         return Response::json(['error' => '#sendmany: ' . ADDRESS_AMOUNT_NOT_SPECIFIED_SEND_MANY]);
     }
     Log::info('=== START PAYMENT to MANY');
     foreach ($recipients as $btc_address => $satoshi_amount) {
         Log::info("Payment to {$btc_address}, note: {$note}, amount: " . self::satoshiToBtc($satoshi_amount));
     }
     Log::info('=== END PAYMENT to MANY');
     $total_satoshis = $this->getSendManyTotalAmount($recipients);
     DB::beginTransaction();
     // begin DB transaction
     $user_balance = Balance::getBalance($this->user->id, $this->crypto_type_id);
     if ($user_balance->balance < $total_satoshis) {
         DB::rollback();
         Log::error('#sendmany: ' . NO_FUNDS);
         return Response::json(['error' => '#payment: ' . NO_FUNDS]);
     }
     $total_satoshis = abs($total_satoshis);
     // make it sure its positive
     $new_balance = bcsub($user_balance->balance, $total_satoshis);
     Log::info('User initial balance: ' . self::satoshiToBtc($user_balance->balance) . ' BTC, new balance: ' . self::satoshiToBtc($new_balance));
     Balance::setNewUserBalance($user_balance, $new_balance);
     $sent = false;
     try {
         // convert satoshis to btc
         $recipients_copy = clone $recipients;
         // need to copy to another array, since satoshis are converted to bitcoin denomination by reference
         $this->bitcoin_core->setRpcConnection($this->user->rpc_connection);
         $addedExtraOutputs = false;
         /* check if that functionality is there */
         if (BitcoinHelper::isMonitoringOutputsEnabled()) {
             // if anything fails in here, just continue sending
             try {
                 /* Check here if there are enough confirmed UTXOs and whether more need to be added
                  * Check of outputs were not checked recently, otherwise query for unspents */
                 $checkedOutputsRecently = Cache::get(self::OUTPUTS_CACHE_KEY);
                 if (!$checkedOutputsRecently) {
                     $outputs = $this->bitcoin_core->listunspent(1);
                     $outputsResponse = new UnspentOutputsResponse($outputs);
                     $total = $outputsResponse->getTotal();
                     $outputsThreshold = BitcoinHelper::getOutputsThreshold();
                     Log::info('Initiating checking outputs, total outputs: ' . $total . '. Outputs threshold: ' . $outputsThreshold);
                     // if total less than 150, create 125 more
                     if ($total < $outputsThreshold) {
                         // send to own addresses some 0.06 or something
                         // get 125 more addresses and create pairs for them
                         $recipients_copy = BitcoinHelper::addOutputsToChangeAddresses($recipients_copy, $this->user->id);
                         // sending email of new transaction hash to email at the end of this method
                         $addedExtraOutputs = true;
                     } else {
                         // not added, just email about it
                         MailHelper::sendAdminEmail(['subject' => 'Enough outputs exists', 'text' => 'No need to add extra. Number of outputs: ' . $outputsResponse->getTotal()]);
                     }
                     // set cache for 45 minutes until next check for outputs
                     $outputsCacheDuration = BitcoinHelper::getOutputsCacheDuration();
                     Cache::put(self::OUTPUTS_CACHE_KEY, 1, $outputsCacheDuration);
                 }
             } catch (Exception $e) {
                 MailHelper::sendAdminEmail(['subject' => 'Failed in adding more outputs', 'text' => "Message\n" . $e->getMessage() . "\nTrace\n" . $e]);
                 // replace back only original recipients
                 $recipients_copy = clone $recipients;
             }
         }
         $recipients_bitcoin_denomination_obj = $this->convertSendManySatoshisToBtc($recipients_copy, false);
         $tx_id = $this->bitcoin_core->sendmany($account, $recipients_bitcoin_denomination_obj, 0, $note);
         $sent = true;
         if ($tx_id) {
             // if it fails here on inserting new transaction, then this transaction will be rolled back - user balance not updated, but jsonrpcclient will send out.
             // think of a clever way on which step it failed and accordingly let know if balance was updated or not
             foreach ($recipients as $address => $amount_satoshi) {
                 $new_transaction = Transaction::insertNewTransaction(['tx_id' => $tx_id, 'user_id' => $this->user->id, 'transaction_type' => TX_SEND, 'crypto_amount' => $amount_satoshi, 'crypto_type_id' => $this->crypto_type_id, 'address_to' => $address, 'note' => $note, 'external_user_id' => $external_user_id]);
             }
         }
     } catch (Exception $e) {
         DB::rollback();
         Log::error("#sendmany: send to address exception: " . $e->getMessage());
         foreach ($recipients as $address => $amount_satoshi) {
             // create identical data first
             $tx_data = ['user_id' => $this->user->id, 'address_to' => $address, 'crypto_amount' => $amount_satoshi, 'error' => $e->getMessage(), 'user_note' => $note, 'sent_to_network' => $sent, 'transaction_type' => TX_SEND, 'external_user_id' => $external_user_id];
             // because transaction was sent to network, decrease API user balance and also insert transaction hash
             if ($sent) {
                 Balance::setNewUserBalance($user_balance, $new_balance);
                 // also decrease balance
                 $tx_data['tx_id'] = $tx_id;
                 // because was sent to network, we know tx_id
                 TransactionFailed::insertTransaction($tx_data);
                 return Response::json(['message' => "#sendmany: send to address exception: " . $e->getMessage(), 'tx_hash' => $tx_id]);
             } else {
                 TransactionFailed::insertTransaction($tx_data);
             }
         }
         // send email
         MailHelper::sendAdminEmail(['subject' => 'Failed in sendmany', 'text' => "Message\n" . $e->getMessage() . "\nTrace\n" . $e]);
         return Response::json(['error' => "#sendmany: send to address exception: " . $e->getMessage()]);
     }
     DB::commit();
     if (isset($new_transaction)) {
         $this->saveFee($new_transaction);
         if ($addedExtraOutputs) {
             // send email about extra outputs with tx hash
             MailHelper::sendAdminEmail(['subject' => 'Added extra outputs', 'text' => "Tx id: {$tx_id}"]);
         }
     }
     return Response::json(['message' => 'Sent To Multiple Recipients', 'tx_hash' => $tx_id]);
 }