public function testCurrentUtilsConversions()
 {
     // float value to satoshis
     PHPUnit::assertEquals(12300000000, CurrencyUtil::valueToSatoshis(123));
     PHPUnit::assertEquals(2100000000000000, CurrencyUtil::valueToSatoshis(21000000));
     PHPUnit::assertEquals(12311111119, CurrencyUtil::valueToSatoshis(123.111111189));
     // satoshis to float value
     PHPUnit::assertEquals(123, CurrencyUtil::satoshisToValue(12300000000));
     PHPUnit::assertEquals(21000000, CurrencyUtil::satoshisToValue(2100000000000000));
     PHPUnit::assertEquals(123.11111119, CurrencyUtil::satoshisToValue(12311111119));
     // satoshisToFormattedString
     PHPUnit::assertEquals('123', CurrencyUtil::satoshisToFormattedString(12300000000));
     PHPUnit::assertEquals('123.4', CurrencyUtil::satoshisToFormattedString(12340000000));
     PHPUnit::assertEquals('1,235.6', CurrencyUtil::satoshisToFormattedString(123560000000));
     // valueToFormattedString
     PHPUnit::assertEquals('1,234.5', CurrencyUtil::valueToFormattedString(1234.5));
 }
 public function buildTransactionData($txid)
 {
     $enhanced_bitcoind_transaction = $this->loadTransactionFromBitcoind($txid);
     // enhance vins
     $enhanced_vins = [];
     foreach ($enhanced_bitcoind_transaction['vin'] as $n => $vin) {
         $enhanced_vins[] = $this->enhanceVin($vin, $n);
     }
     $enhanced_bitcoind_transaction['vin'] = $enhanced_vins;
     // values in, out and fees
     $enhanced_bitcoind_transaction['valueIn'] = 0.0;
     $enhanced_bitcoind_transaction['valueInSat'] = $this->sumValuesIn($enhanced_vins);
     $enhanced_bitcoind_transaction['valueIn'] = CurrencyUtil::satoshisToValue($enhanced_bitcoind_transaction['valueInSat']);
     $enhanced_bitcoind_transaction['valueOut'] = $this->sumValuesOut($enhanced_bitcoind_transaction['vout']);
     $enhanced_bitcoind_transaction['valueOutSat'] = CurrencyUtil::valueToSatoshis($enhanced_bitcoind_transaction['valueOut']);
     $enhanced_bitcoind_transaction['fees'] = 0.0;
     $enhanced_bitcoind_transaction['feesSat'] = $enhanced_bitcoind_transaction['valueInSat'] - $enhanced_bitcoind_transaction['valueOutSat'];
     $enhanced_bitcoind_transaction['fees'] = CurrencyUtil::satoshisToValue($enhanced_bitcoind_transaction['feesSat']);
     return $enhanced_bitcoind_transaction;
 }
Пример #3
0
 /**
  * Get all balances for an address
  *
  * @param  int  $id
  * @return Response
  */
 public function show(Client $xcpd_client, BitcoinPayer $bitcoin_payer, Cache $asset_info_cache, $address)
 {
     if (!AddressValidator::isValid($address)) {
         $message = "The address {$address} was not valid";
         EventLog::logError('error.getBalance', ['address' => $address, 'message' => $message]);
         return new JsonResponse(['message' => $message], 500);
     }
     $balances = $xcpd_client->get_balances(['filters' => ['field' => 'address', 'op' => '==', 'value' => $address]]);
     // and get BTC balance too
     $btc_float_balance = $bitcoin_payer->getBalance($address);
     $balances = array_merge([['asset' => 'BTC', 'quantity' => $btc_float_balance]], $balances);
     $out = ['balances' => [], 'balancesSat' => []];
     foreach ($balances as $balance) {
         $asset_name = $balance['asset'];
         if ($asset_name == 'BTC') {
             // BTC quantity is a float
             $quantity_float = floatval($balance['quantity']);
             $quantity_sat = CurrencyUtil::valueToSatoshis($balance['quantity']);
         } else {
             // determine quantity based on asset info
             $is_divisible = $asset_info_cache->isDivisible($asset_name);
             if ($is_divisible) {
                 $quantity_float = CurrencyUtil::satoshisToValue($balance['quantity']);
                 $quantity_sat = intval($balance['quantity']);
             } else {
                 // non-divisible assets don't use satoshis
                 $quantity_float = floatval($balance['quantity']);
                 $quantity_sat = CurrencyUtil::valueToSatoshis($balance['quantity']);
             }
         }
         $out['balances'][$asset_name] = $quantity_float;
         $out['balancesSat'][$asset_name] = $quantity_sat;
     }
     ksort($out['balances']);
     ksort($out['balancesSat']);
     return json_encode($out);
 }
Пример #4
0
 /**
  * gets a list of the current UTXOs that are primed
  *
  * @return Response
  */
 public function getPrimedUTXOs($address_uuid, Guard $auth, Request $request, APIControllerHelper $helper, PaymentAddressRepository $payment_address_repository, TXORepository $txo_repository)
 {
     try {
         $user = $auth->getUser();
         if (!$user) {
             throw new Exception("User not found", 1);
         }
         $payment_address = $helper->requireResourceOwnedByUser($address_uuid, $user, $payment_address_repository);
         $size = floatval($request->query('size'));
         if ($size <= 0) {
             throw new Exception("Invalid size", 400);
         }
         $size_satoshis = CurrencyUtil::valueToSatoshis($size);
         // get the UTXOs
         //   [TXO::UNCONFIRMED, TXO::CONFIRMED]
         $txos = $this->filterGreenOrConfirmedUTXOs($txo_repository->findByPaymentAddress($payment_address, null, true));
         // count the number that match the size
         $matching_count = 0;
         $total_count = 0;
         $filtered_txos = [];
         foreach ($txos as $txo) {
             if ($txo['amount'] == $size_satoshis) {
                 ++$matching_count;
             }
             $filtered_txos[] = ['txid' => $txo['txid'], 'n' => $txo['n'], 'amount' => CurrencyUtil::satoshisToValue($txo['amount']), 'type' => TXO::typeIntegerToString($txo['type']), 'green' => !!$txo['type']];
             ++$total_count;
         }
         $output = ['primedCount' => $matching_count, 'totalCount' => $total_count, 'utxos' => $filtered_txos];
         return $helper->buildJSONResponse($output);
     } catch (Exception $e) {
         if ($e->getCode() >= 400 and $e->getCode() < 500) {
             throw new HttpResponseException(new JsonResponse(['errors' => [$e->getMessage()]], 400));
         }
         throw $e;
     }
 }
 public function buildParsedTransactionData($bitcoin_transaction_data, $ts)
 {
     try {
         $parsed_transaction_data = [];
         $parsed_transaction_data = ['txid' => $bitcoin_transaction_data['txid'], 'network' => 'bitcoin', 'timestamp' => round($ts / 1000), 'counterPartyTxType' => false, 'sources' => [], 'destinations' => [], 'values' => [], 'asset' => false, 'bitcoinTx' => $bitcoin_transaction_data, 'counterpartyTx' => []];
         $xcp_data = $this->parser->parseBitcoinTransaction($bitcoin_transaction_data);
         if ($xcp_data) {
             // ensure 1 source and 1 desination
             if (!isset($xcp_data['sources'][0])) {
                 $xcp_data['sources'] = ['unknown'];
                 Log::error("No source found in transaction: " . ((isset($bitcoin_transaction_data) and isset($bitcoin_transaction_data['txid'])) ? $bitcoin_transaction_data['txid'] : "unknown"));
             }
             if (!isset($xcp_data['destinations'][0])) {
                 $xcp_data['destinations'] = ['unknown'];
                 Log::error("No destination found in transaction: " . ((isset($bitcoin_transaction_data) and isset($bitcoin_transaction_data['txid'])) ? $bitcoin_transaction_data['txid'] : "unknown"));
             }
             // this is a counterparty transaction
             $parsed_transaction_data['network'] = 'counterparty';
             $parsed_transaction_data['counterPartyTxType'] = $xcp_data['type'];
             $parsed_transaction_data['sources'] = $xcp_data['sources'];
             $parsed_transaction_data['destinations'] = $xcp_data['destinations'];
             if ($xcp_data['type'] === 'send') {
                 $is_divisible = $this->asset_cache->isDivisible($xcp_data['asset']);
                 // if the asset info doesn't exist, assume it is divisible
                 if ($is_divisible === null) {
                     $is_divisible = true;
                 }
                 if ($is_divisible) {
                     $quantity_sat = $xcp_data['quantity'];
                     $quantity_float = CurrencyUtil::satoshisToValue($xcp_data['quantity']);
                 } else {
                     $quantity_sat = CurrencyUtil::valueToSatoshis($xcp_data['quantity']);
                     $quantity_float = intval($xcp_data['quantity']);
                 }
                 $xcp_data['quantity'] = $quantity_float;
                 $xcp_data['quantitySat'] = $quantity_sat;
                 $destination = $xcp_data['destinations'][0];
                 $parsed_transaction_data['values'] = [$destination => $quantity_float];
                 $parsed_transaction_data['asset'] = $xcp_data['asset'];
                 // dustSize
                 // dustSizeSat
                 list($sources, $quantity_by_destination) = $this->extractSourcesAndDestinations($bitcoin_transaction_data);
                 $dust_size_float = isset($quantity_by_destination[$destination]) ? $quantity_by_destination[$destination] : 0;
                 $xcp_data['dustSize'] = $dust_size_float;
                 $xcp_data['dustSizeSat'] = CurrencyUtil::valueToSatoshis($dust_size_float);
             }
             // Log::debug("\$xcp_data=".json_encode($xcp_data, 192));
             $parsed_transaction_data['counterpartyTx'] = $xcp_data;
         } else {
             // this is just a bitcoin transaction
             list($sources, $quantity_by_destination) = $this->extractSourcesAndDestinations($bitcoin_transaction_data);
             $parsed_transaction_data['network'] = 'bitcoin';
             $parsed_transaction_data['sources'] = $sources;
             $parsed_transaction_data['destinations'] = array_keys($quantity_by_destination);
             $parsed_transaction_data['values'] = $quantity_by_destination;
             $parsed_transaction_data['asset'] = 'BTC';
         }
         // add a blockheight
         if (isset($parsed_transaction_data['bitcoinTx']['blockhash']) and $hash = $parsed_transaction_data['bitcoinTx']['blockhash']) {
             $block = $this->blockchain_store->findByHash($hash);
             $parsed_transaction_data['bitcoinTx']['blockheight'] = $block ? $block['height'] : null;
         }
         // add a transaction fingerprint
         $parsed_transaction_data['transactionFingerprint'] = $this->buildFingerprint($parsed_transaction_data['bitcoinTx']);
         return $parsed_transaction_data;
     } catch (Exception $e) {
         Log::warning("Failed to parse transaction: " . ((isset($bitcoin_transaction_data) and isset($bitcoin_transaction_data['txid'])) ? $bitcoin_transaction_data['txid'] : "unknown") . "\n" . $e->getMessage());
         // print "ERROR: ".$e->getMessage()."\n";
         // echo "\$parsed_transaction_data:\n".json_encode($parsed_transaction_data, 192)."\n";
         throw $e;
     }
 }
Пример #6
0
 protected function debugDumpUTXOs($utxos)
 {
     $out = '';
     $out .= 'total utxos: ' . count($utxos) . "\n";
     foreach ($utxos as $utxo) {
         $out .= '  ' . $utxo['txid'] . ':' . $utxo['n'] . ' (' . CurrencyUtil::satoshisToValue($utxo['amount']) . ')' . "\n";
     }
     return rtrim($out);
 }
Пример #7
0
 protected function assembleAccountBalancesWithTXID($results, $in_satoshis = false)
 {
     $sums = array_fill_keys(LedgerEntry::allTypeStrings(), []);
     foreach ($results as $result) {
         $txid = $result['txid'];
         if (!$txid) {
             $txid = 'none';
         }
         if ($in_satoshis) {
             $sums[LedgerEntry::typeIntegerToString($result['type'])][$txid][$result['asset']] = $result['total_amount'];
         } else {
             $sums[LedgerEntry::typeIntegerToString($result['type'])][$txid][$result['asset']] = CurrencyUtil::satoshisToValue($result['total_amount']);
         }
     }
     return $sums;
 }
Пример #8
0
 /**
  * Execute the console command.
  *
  * @return mixed
  */
 public function fire()
 {
     $ledger = app('App\\Repositories\\LedgerEntryRepository');
     $payment_address_repo = app('App\\Repositories\\PaymentAddressRepository');
     $account_repository = app('App\\Repositories\\AccountRepository');
     $user_repository = app('App\\Repositories\\UserRepository');
     $xcpd_client = app('Tokenly\\XCPDClient\\Client');
     $bitcoin_payer = app('Tokenly\\BitcoinPayer\\BitcoinPayer');
     $asset_info_cache = app('Tokenly\\CounterpartyAssetInfoCache\\Cache');
     $payment_address_uuid = $this->input->getArgument('payment-address-uuid');
     if ($payment_address_uuid) {
         $payment_address = $payment_address_repo->findByUuid($payment_address_uuid);
         if (!$payment_address) {
             throw new Exception("Payment address not found", 1);
         }
         $payment_addresses = [$payment_address];
     } else {
         $payment_addresses = $payment_address_repo->findAll();
     }
     foreach ($payment_addresses as $payment_address) {
         Log::debug("reconciling accounts for {$payment_address['address']} ({$payment_address['uuid']})");
         // get XCP balances
         $balances = $xcpd_client->get_balances(['filters' => ['field' => 'address', 'op' => '==', 'value' => $payment_address['address']]]);
         // and get BTC balance too
         $btc_float_balance = $bitcoin_payer->getBalance($payment_address['address']);
         $balances = array_merge([['asset' => 'BTC', 'quantity' => $btc_float_balance]], $balances);
         // get xchain balances
         $raw_xchain_balances_by_type = $ledger->combinedAccountBalancesByAsset($payment_address, null);
         // echo "\$raw_xchain_balances_by_type: ".json_encode($raw_xchain_balances_by_type, 192)."\n";
         $combined_xchain_balances = [];
         foreach ($raw_xchain_balances_by_type as $type_string => $xchain_balances) {
             foreach ($xchain_balances as $asset => $quantity) {
                 if ($type_string == 'sending' and $asset == 'BTC') {
                     continue;
                 }
                 if ($type_string == 'unconfirmed' and $asset != 'BTC') {
                     continue;
                 }
                 if (!isset($combined_xchain_balances[$asset])) {
                     $combined_xchain_balances[$asset] = 0.0;
                 }
                 $combined_xchain_balances[$asset] += $quantity;
             }
         }
         // get daemon balances
         $daemon_balances = [];
         foreach ($balances as $balance) {
             $asset_name = $balance['asset'];
             if ($asset_name == 'BTC') {
                 // BTC quantity is a float
                 $quantity_float = floatval($balance['quantity']);
             } else {
                 // determine quantity based on asset info
                 $is_divisible = $asset_info_cache->isDivisible($asset_name);
                 if ($is_divisible) {
                     $quantity_float = CurrencyUtil::satoshisToValue($balance['quantity']);
                 } else {
                     // non-divisible assets don't use satoshis
                     $quantity_float = floatval($balance['quantity']);
                 }
             }
             $daemon_balances[$asset_name] = $quantity_float;
         }
         // compare
         $differences = $this->buildDifferences($combined_xchain_balances, $daemon_balances);
         if ($differences['any']) {
             $this->comment("Differences found for {$payment_address['address']} ({$payment_address['uuid']})");
             $this->line(json_encode($differences, 192));
             $this->line('');
         } else {
             Log::debug("no differences for {$payment_address['address']} ({$payment_address['uuid']})");
             if ($payment_address_uuid) {
                 // only showing one address
                 $this->comment("No differences found for {$payment_address['address']} ({$payment_address['uuid']})");
             }
         }
     }
     $this->info('done');
 }
Пример #9
0
 public function testAPICreatePrimes_2()
 {
     $this->app->make('CounterpartySenderMockBuilder')->installMockCounterpartySenderDependencies($this->app, $this);
     // setup
     list($payment_address, $sample_txos) = $this->setupPrimes();
     // api tester
     $api_tester = $this->getAPITester();
     $create_primes_vars = ['size' => CurrencyUtil::satoshisToValue(5430), 'count' => 2];
     $response = $api_tester->callAPIWithAuthentication('POST', '/api/v1/primes/' . $payment_address['uuid'], $create_primes_vars);
     $api_data = json_decode($response->getContent(), true);
     PHPUnit::assertEquals(0, $api_data['oldPrimedCount']);
     PHPUnit::assertEquals(2, $api_data['newPrimedCount']);
     PHPUnit::assertEquals(true, $api_data['primed']);
     // check the composed transaction
     $composed_transaction_raw = DB::connection('untransacted')->table('composed_transactions')->first();
     $send_data = app('TransactionComposerHelper')->parseBTCTransaction($composed_transaction_raw->transaction);
     $bitcoin_address = $payment_address['address'];
     PHPUnit::assertCount(2, $send_data['change']);
     PHPUnit::assertEquals($bitcoin_address, $send_data['destination']);
     PHPUnit::assertEquals(5430, $send_data['btc_amount']);
     PHPUnit::assertEquals($bitcoin_address, $send_data['change'][0][0]);
     PHPUnit::assertEquals(5430, $send_data['change'][0][1]);
 }
Пример #10
0
 public function testChooseTXOsFour()
 {
     // receiving a transaction adds TXOs
     $txo_repository = app('App\\Repositories\\TXORepository');
     $txo_chooser = app('App\\Blockchain\\Sender\\TXOChooser');
     $float = function ($i) {
         return CurrencyUtil::satoshisToValue($i);
     };
     list($payment_address, $sample_txos) = $this->makeAddressAndSampleTXOs_4();
     // choose exact change from a bunch
     $chosen_txos = $txo_chooser->chooseUTXOs($payment_address, 0.0005, 0.0001, $float(5430));
     // $this->assertFound([2,1,3,4], $sample_txos, $chosen_txos);
 }
Пример #11
0
 protected function executeSend(APIControllerHelper $helper, Request $request, PaymentAddressRepository $payment_address_respository, SendRepository $send_respository, PaymentAddressSender $address_sender, Guard $auth, APICallRepository $api_call_repository, $id)
 {
     $user = $auth->getUser();
     if (!$user) {
         throw new Exception("User not found", 1);
     }
     // get the address
     $payment_address = $payment_address_respository->findByUuid($id);
     if (!$payment_address) {
         return new JsonResponse(['message' => 'address not found'], 404);
     }
     // make sure this address belongs to this user
     if ($payment_address['user_id'] != $user['id']) {
         return new JsonResponse(['message' => 'Not authorized to send from this address'], 403);
     }
     // attributes
     $request_attributes = $request->only(array_keys($request->rules()));
     // determine if this is a multisend
     $is_multisend = (isset($request_attributes['destinations']) and $request_attributes['destinations']);
     $is_regular_send = !$is_multisend;
     // normalize destinations
     $destinations = $is_multisend ? $this->normalizeDestinations($request_attributes['destinations']) : '';
     $destination = $is_regular_send ? $request_attributes['destination'] : '';
     // determine variables
     $quantity_sat = CurrencyUtil::valueToSatoshis($is_multisend ? $this->sumMultisendQuantity($destinations) : $request_attributes['quantity']);
     $asset = $is_regular_send ? $request_attributes['asset'] : 'BTC';
     $is_sweep = isset($request_attributes['sweep']) ? !!$request_attributes['sweep'] : false;
     $float_fee = isset($request_attributes['fee']) ? $request_attributes['fee'] : PaymentAddressSender::DEFAULT_FEE;
     $dust_size = isset($request_attributes['dust_size']) ? $request_attributes['dust_size'] : PaymentAddressSender::DEFAULT_REGULAR_DUST_SIZE;
     $request_id = isset($request_attributes['requestId']) ? $request_attributes['requestId'] : Uuid::uuid4()->toString();
     // create attibutes
     $create_attributes = [];
     $create_attributes['user_id'] = $user['id'];
     $create_attributes['payment_address_id'] = $payment_address['id'];
     $create_attributes['destination'] = $destination;
     $create_attributes['quantity_sat'] = $quantity_sat;
     $create_attributes['asset'] = $asset;
     $create_attributes['is_sweep'] = $is_sweep;
     $create_attributes['fee'] = $float_fee;
     $create_attributes['dust_size'] = $dust_size;
     // for multisends
     $create_attributes['destinations'] = $destinations;
     // the transaction must be committed before the lock is release and not after
     //   therefore we must release the lock after this closure completes
     $lock_must_be_released = false;
     $lock_must_be_released_with_delay = false;
     // create a send and lock it immediately
     $send_result = $send_respository->executeWithNewLockedSendByRequestID($request_id, $create_attributes, function ($locked_send) use($request_attributes, $create_attributes, $payment_address, $user, $helper, $send_respository, $address_sender, $api_call_repository, $request_id, $is_multisend, $is_regular_send, $quantity_sat, $asset, $destination, $destinations, $is_sweep, $float_fee, $dust_size, &$lock_must_be_released, &$lock_must_be_released_with_delay) {
         $api_call = $api_call_repository->create(['user_id' => $user['id'], 'details' => ['method' => 'api/v1/sends/' . $payment_address['uuid'], 'args' => $request_attributes]]);
         // if a send already exists by this request_id, just return it
         if (isset($locked_send['txid']) && strlen($locked_send['txid'])) {
             EventLog::log('send.alreadyFound', $locked_send);
             return $helper->transformResourceForOutput($locked_send);
         }
         $float_quantity = CurrencyUtil::satoshisToValue($quantity_sat);
         // send
         EventLog::log('send.requested', array_merge($request_attributes, $create_attributes));
         if ($is_sweep) {
             try {
                 // get lock
                 $lock_acquired = AccountHandler::acquirePaymentAddressLock($payment_address);
                 if ($lock_acquired) {
                     $lock_must_be_released = true;
                 }
                 list($txid, $float_balance_sent) = $address_sender->sweepAllAssets($payment_address, $request_attributes['destination'], $float_fee);
                 $quantity_sat_sent = CurrencyUtil::valueToSatoshis($float_balance_sent);
                 // clear all balances from all accounts
                 AccountHandler::zeroAllBalances($payment_address, $api_call);
                 // release the account lock with a slight delay
                 if ($lock_acquired) {
                     $lock_must_be_released_with_delay = true;
                 }
             } catch (PaymentException $e) {
                 EventLog::logError('error.sweep', $e);
                 return new JsonResponse(['message' => $e->getMessage()], 500);
             } catch (Exception $e) {
                 EventLog::logError('error.sweep', $e);
                 return new JsonResponse(['message' => 'Unable to complete this request'], 500);
             }
         } else {
             try {
                 // get the account
                 $account_name = (isset($request_attributes['account']) and strlen($request_attributes['account'])) ? $request_attributes['account'] : 'default';
                 $account = AccountHandler::getAccount($payment_address, $account_name);
                 if (!$account) {
                     EventLog::logError('error.send.accountMissing', ['address_id' => $payment_address['id'], 'account' => $account_name]);
                     return new JsonResponse(['message' => "This account did not exist."], 404);
                 }
                 // Log::debug("\$account=".json_encode($account, 192));
                 // get lock
                 $lock_acquired = AccountHandler::acquirePaymentAddressLock($payment_address);
                 if ($lock_acquired) {
                     $lock_must_be_released = true;
                 }
                 // whether to spend unconfirmed balances
                 $allow_unconfirmed = isset($request_attributes['unconfirmed']) ? $request_attributes['unconfirmed'] : false;
                 // Log::debug("\$allow_unconfirmed=".json_encode($allow_unconfirmed, 192));
                 // validate that the funds are available
                 if ($allow_unconfirmed) {
                     $has_enough_funds = AccountHandler::accountHasSufficientFunds($account, $float_quantity, $asset, $float_fee, $dust_size);
                 } else {
                     $has_enough_funds = AccountHandler::accountHasSufficientConfirmedFunds($account, $float_quantity, $asset, $float_fee, $dust_size);
                 }
                 if (!$has_enough_funds) {
                     EventLog::logError('error.send.insufficient', ['address_id' => $payment_address['id'], 'account' => $account_name, 'quantity' => $float_quantity, 'asset' => $asset]);
                     return new JsonResponse(['message' => "This account does not have sufficient" . ($allow_unconfirmed ? '' : ' confirmed') . " funds available."], 400);
                 }
                 // send the funds
                 EventLog::log('send.begin', ['request_id' => $request_id, 'address_id' => $payment_address['id'], 'account' => $account_name, 'quantity' => $float_quantity, 'asset' => $asset, 'destination' => $is_multisend ? $destinations : $destination]);
                 $txid = $address_sender->sendByRequestID($request_id, $payment_address, $is_multisend ? $destinations : $destination, $float_quantity, $asset, $float_fee, $dust_size);
                 EventLog::log('send.complete', ['txid' => $txid, 'request_id' => $request_id, 'address_id' => $payment_address['id'], 'account' => $account_name, 'quantity' => $float_quantity, 'asset' => $asset, 'destination' => $is_multisend ? $destinations : $destination]);
                 // tag funds as sent with the txid
                 if ($allow_unconfirmed) {
                     AccountHandler::markAccountFundsAsSending($account, $float_quantity, $asset, $float_fee, $dust_size, $txid);
                 } else {
                     AccountHandler::markConfirmedAccountFundsAsSending($account, $float_quantity, $asset, $float_fee, $dust_size, $txid);
                     // Log::debug("After marking confirmed funds as sent, all accounts for ${account['name']}: ".json_encode(app('App\Repositories\LedgerEntryRepository')->accountBalancesByAsset($account, null), 192));
                     // Log::debug("After marking confirmed funds as sent, all accounts for default: ".json_encode(app('App\Repositories\LedgerEntryRepository')->accountBalancesByAsset(AccountHandler::getAccount($payment_address), null), 192));
                 }
                 // release the account lock
                 if ($lock_acquired) {
                     $lock_must_be_released_with_delay = true;
                 }
             } catch (AccountException $e) {
                 EventLog::logError('error.pay', $e);
                 return new JsonResponse(['message' => $e->getMessage(), 'errorName' => $e->getErrorName()], $e->getStatusCode());
             } catch (PaymentException $e) {
                 EventLog::logError('error.pay', $e);
                 return new JsonResponse(['message' => $e->getMessage()], 500);
             } catch (Exception $e) {
                 EventLog::logError('error.pay', $e);
                 return new JsonResponse(['message' => 'Unable to complete this request'], 500);
             }
         }
         $attributes = [];
         $attributes['sent'] = time();
         $attributes['txid'] = $txid;
         EventLog::log('send.complete', $attributes);
         // update and send response
         $send_respository->update($locked_send, $attributes);
         return $helper->buildJSONResponse($locked_send->serializeForAPI());
     }, self::SEND_LOCK_TIMEOUT);
     // make sure to release the lock
     if ($lock_must_be_released_with_delay) {
         $this->releasePaymentAddressLockWithDelay($payment_address);
     } else {
         if ($lock_must_be_released) {
             AccountHandler::releasePaymentAddressLock($payment_address);
         }
     }
     return $send_result;
 }
Пример #12
0
 protected function normalizeBitcoindUTXORecord($unspent_txo_record)
 {
     return ['address' => $unspent_txo_record->destination_address, 'txid' => $unspent_txo_record->txid, 'vout' => $unspent_txo_record->n, 'script' => $unspent_txo_record->script, 'amount' => CurrencyUtil::satoshisToValue($unspent_txo_record->destination_value), 'amount_sat' => $unspent_txo_record->destination_value, 'confirmations' => $unspent_txo_record->confirmations, 'confirmed' => $unspent_txo_record->confirmations > 0];
 }
Пример #13
0
 public function getDustSizeAttribute()
 {
     return CurrencyUtil::satoshisToValue($this->attributes['dust_size_sat']);
 }
Пример #14
0
 /**
  * Returns the value as a float
  * @return float value as a float
  */
 public function getFloat()
 {
     return CurrencyUtil::satoshisToValue($this->satoshis_qty);
 }