Пример #1
0
 /**
  * Execute the console command.
  *
  * @return mixed
  */
 public function handle()
 {
     $request = Request::create('/api/blocknotify', 'GET', ['key' => Mint\Settings::getVal('api_key'), 'blockhash' => $this->argument('blockhash')]);
     Request::replace($request->input());
     $response = Route::dispatch($request)->getContent();
     if ($this->option('debug')) {
         $this->info($response);
     }
 }
Пример #2
0
 /**
  * Execute the console command.
  *
  * @return mixed
  */
 public function handle()
 {
     $pid = (int) getmypid();
     $txid = $this->argument('txid');
     Log::info('ApiCallback(txid: ' . $txid . ', pid:' . $pid . '): Running...');
     /* Acquire lock to prevent double execution */
     $fp = fopen(storage_path('locks/mint-' . $txid . '.lock'), 'w');
     if (!flock($fp, LOCK_EX | LOCK_NB)) {
         Log::error('ApiCallback(txid: ' . $txid . ', pid:' . $pid . '): Task is already running! Halting...');
         exit;
     }
     $request = Request::create('/api/callback', 'GET', ['key' => Mint\Settings::getVal('api_key'), 'txid' => $this->argument('txid')]);
     Request::replace($request->input());
     $response = Route::dispatch($request)->getContent();
     if ($this->option('debug')) {
         $this->info($response);
     }
     /* Release lock after finishing execution */
     flock($fp, LOCK_UN);
     fclose($fp);
     unlink(storage_path('locks/mint-' . $txid . '.lock'));
 }
Пример #3
0
 /**
  * Send from address or address account
  *
  * @return mixed
  */
 private function sendFrom($from_address, $to_address, $note = '', Converter $amount, Converter $network_fee)
 {
     $from_address_model = Mint\Address::getAddress($from_address);
     $is_internal = $this->isUserAddress($to_address);
     $merchant_fee = Converter::btc(Mint\Settings::getVal('merchant_fee'));
     /* Calculate real amount to be deducted from users account. */
     $full_amount = !$is_internal ? Converter::satoshi($this->bcsum($amount->satoshi, $network_fee->satoshi, $merchant_fee->satoshi)) : $amount;
     /* If it's users address check balance without fee */
     if ($from_address_model->balance < $full_amount->satoshi) {
         throw new JsonException(trans('error.nofunds'));
     }
     if (!$is_internal) {
         /* Set transaction fee and deduct it from the payment amount */
         $this->bitcoin_core->settxfee((double) $network_fee->btc);
         $amount = Converter::btc(bcsub($amount->btc, $network_fee->btc, 8));
         /* Pay merchant fee and deduct it from the payment amount if any */
         if ($merchant_fee->satoshi > 0) {
             $fee_address = $this->getFeeAddress();
             $this->sendFrom($from_address_model->address, $fee_address, 'merchant fee', $merchant_fee, Converter::btc(0));
             $amount = Converter::btc(bcsub($amount->btc, $merchant_fee->btc, 8));
         }
         /* Refund merchant fee if payment fails */
         try {
             $tx_id = $this->bitcoin_core->sendfrom($from_address, $to_address, (double) $amount->btc, 1, $note);
         } catch (JsonException $e) {
             $this->sendFrom($fee_address, $from_address_model->address, 'merchant fee refund', $merchant_fee, Converter::btc(0));
             throw new JsonException($e->getMessage());
         }
         $tx_info = $this->bitcoin_core->gettransaction($tx_id);
         $tx_fee = Converter::btc(abs($tx_info['fee']));
     } else {
         /* Internal transaction. No txid returned and no fee required. */
         $tx_id = 0;
         $tx_fee = Converter::btc(0);
         $merchant_fee = Converter::btc(0);
         $to_address_model = Mint\Address::getAddress($to_address);
         /* Move currency between user accounts. */
         $response = $this->bitcoin_core->move($from_address_model->address, $to_address_model->address, (double) $amount->btc, 1, $note);
         if (!$response) {
             throw new JsonException(trans('error.movefailed'));
         }
         /* Update every balance, because we won't be getting callback on move */
         Mint\Address::updateAddressBalance($from_address_model, -$amount->satoshi);
         $address_model = Mint\Address::updateAddressBalance($to_address_model, $amount->satoshi);
         /* Update user balance if this transaction is fee */
         $user_balance = Mint\Balance::getBalance($this->user->id);
         if ($to_address_model->address == $this->getFeeAddress()) {
             $user_balance = Mint\Balance::updateUserBalance($this->user, -$amount->satoshi);
         }
         /* Add bogus transaction to db and send callback */
         foreach (['send', 'receive'] as $type) {
             $common_data = ['tx_id' => '0000000000000000000000000000000000000000000000000000000000000000', 'user_id' => $this->user->id, 'address_from' => $from_address_model->address, 'address_to' => $to_address_model->address, 'crypto_amount' => $type == 'send' ? -$amount->satoshi : $amount->satoshi, 'confirmations' => Mint\Settings::getVal('min_confirmations'), 'network_fee' => 0, 'merchant_fee' => 0, 'tx_time' => time(), 'tx_timereceived' => time(), 'user_balance' => $user_balance->balance, 'address_balance' => $address_model->balance, 'bitcoind_balance' => $this->bitcoin_core->getbalance(), 'note' => $note, 'transaction_type' => 'internal-' . $type];
             $transaction_model = Mint\Transaction::insertNewTransaction($common_data);
             if (!empty($this->user->callback_url)) {
                 $this->fetchUrl($this->user->callback_url, $common_data, $transaction_model);
             }
         }
     }
     return ['tx_id' => $tx_id, 'tx_fee' => $tx_fee, 'merchant_fee' => $merchant_fee, 'amount' => $amount, 'from_address' => $from_address, 'to_address' => $to_address, 'is_internal' => $tx_id === 0];
 }
Пример #4
0
 /**
  * Send from address or address account
  *
  * @return mixed
  */
 private function sendFrom($from_address, $to_address, $note = '', Converter $amount, Converter $network_fee, Converter $merchant_fee, $method = 'sendfrom')
 {
     $from_address_model = Mint\Address::getAddress($from_address);
     if ($method == 'move') {
         if (!$this->isUserAddress($to_address)) {
             $method = 'sendfrom';
         }
     }
     /* Check balance */
     if ($from_address_model->balance < $amount->satoshi) {
         throw new JsonException(trans('error.nofunds'));
     }
     /* Pay merchant fee if any */
     if ($merchant_fee->satoshi > 0) {
         $fee_address = $this->getFeeAddress();
         $this->sendFrom($from_address_model->address, $fee_address, 'merchant fee', $merchant_fee, Converter::btc(0), Converter::btc(0), 'move');
     }
     try {
         if ($method == 'move') {
             $to_address_model = Mint\Address::getAddress($to_address);
             /* Move currency between user accounts. */
             $response = $this->bitcoin_core->move($from_address_model->address, $to_address_model->address, (double) $amount->btc, 1, $note);
             if (!$response) {
                 throw new JsonException(trans('error.movefailed'));
             }
             /* Internal transaction. No txid returned and no network fee required. */
             $tx_id = 0;
             $tx_fee = Converter::btc(0);
             $send_amount = Converter::satoshi(bcadd($amount->satoshi, $merchant_fee->satoshi));
             DB::beginTransaction();
             /* Update every balance, because we won't be getting callback on move */
             Mint\Address::updateAddressBalance($from_address_model, -$send_amount->satoshi);
             $address_model = Mint\Address::updateAddressBalance($to_address_model, $send_amount->satoshi);
             switch (true) {
                 case $to_address_model->address == $this->getFeeAddress():
                     /* Update user balance if this transaction is fee */
                     $user_balance = Mint\Balance::updateUserBalance($this->user, -$send_amount->satoshi);
                     $types = ['send'];
                     break;
                 case $from_address_model->address == $this->getFeeAddress():
                     /* Update user balance if this transaction is fee */
                     $user_balance = Mint\Balance::updateUserBalance($this->user, $send_amount->satoshi);
                     $types = ['receive'];
                     break;
                 default:
                     $user_balance = Mint\Balance::getBalance($this->user->id);
                     $types = ['send', 'receive'];
                     break;
             }
             DB::commit();
             list($usecs, $secs) = explode(' ', microtime());
             $txid = $this->getInternalTxId($from_address_model->address, $to_address_model->address, $amount->satoshi, (double) $secs + (double) $usecs);
             foreach ($types as $type) {
                 $common_data = ['tx_id' => $txid, 'user_id' => $this->user->id, 'address_from' => $from_address_model->address, 'address_to' => $to_address_model->address, 'crypto_amount' => $type == 'send' ? -$amount->satoshi : $amount->satoshi, 'confirmations' => Mint\Settings::getVal('min_confirmations'), 'network_fee' => 0, 'merchant_fee' => $merchant_fee->satoshi, 'tx_time' => (int) $secs, 'tx_timereceived' => (int) $secs, 'tx_category' => $type, 'user_balance' => $user_balance->balance, 'address_balance' => $address_model->balance, 'bitcoind_balance' => $this->bitcoin_core->getbalance(), 'note' => $note, 'transaction_type' => 'internal'];
                 $transaction_model = Mint\Transaction::insertNewTransaction($common_data);
                 if (!empty($this->user->callback_url)) {
                     $this->fetchUrl($this->user->callback_url, $common_data, $transaction_model);
                 }
             }
         } else {
             /* Set transaction fee and deduct it from the payment amount */
             $this->bitcoin_core->settxfee((double) $network_fee->btc);
             $total_amount = Converter::btc(bcsub($amount->btc, $network_fee->btc, 8));
             $tx_id = $this->bitcoin_core->sendfrom($from_address, $to_address, (double) $amount->btc, 1, $note);
             $tx_info = $this->bitcoin_core->gettransaction($tx_id);
             $tx_fee = Converter::btc(abs($tx_info['fee']));
         }
     } catch (JsonException $e) {
         /* Refund merchant fee if payment fails */
         $this->sendFrom($fee_address, $from_address_model->address, 'merchant fee refund', $merchant_fee, Converter::btc(0), Converter::btc(0), 'move');
         throw new JsonException($e->getMessage());
     }
     return ['tx_id' => $tx_id, 'tx_fee' => $tx_fee, 'merchant_fee' => $merchant_fee, 'amount' => $amount, 'from_address' => $from_address, 'to_address' => $to_address, 'is_internal' => $tx_id === 0];
 }