/** * 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 invalidate($parsed_tx) { DB::transaction(function () use($parsed_tx) { $txid = $parsed_tx['txid']; $existing_txos = $this->txo_repository->findByTXID($txid); if (count($existing_txos) == 0) { return; } // delete each txo foreach ($existing_txos as $existing_txo) { Log::debug("invalidate TXO: {$existing_txo['txid']}:{$existing_txo['n']}/" . CurrencyUtil::valueToSatoshis($existing_txo['amount']) . " " . TXO::typeIntegerToString($existing_txo['type']) . " from " . $existing_txo['payment_address_id']); $this->txo_repository->delete($existing_txo); } }); }
public function testSendingFromOnePaymentAddressToAnother() { // receiving a transaction adds TXOs $txo_repository = $this->app->make('App\\Repositories\\TXORepository'); // setup monitors $payment_address_helper = app('PaymentAddressHelper'); $sending_address_one = $payment_address_helper->createSamplePaymentAddress(null, ['address' => '1AuTJDwH6xNqxRLEjPB7m86dgmerYVQ5G1']); $receiving_address_one = $payment_address_helper->createSamplePaymentAddressWithoutInitialBalances(null, ['address' => '1JztLWos5K7LsqW5E78EASgiVBaCe6f7cD']); // create some TXOs $sample_txos = []; $txid = $this->TXOHelper()->nextTXID(); $sample_txos[0] = $this->TXOHelper()->createSampleTXO($sending_address_one, ['txid' => $txid, 'n' => 0]); $sample_txos[1] = $this->TXOHelper()->createSampleTXO($sending_address_one, ['txid' => $txid, 'n' => 1]); // send from sender to receiver $sending_tx = $this->buildTransactionWithUTXOs([$sample_txos[0]]); $this->sendTransactionWithConfirmations($sending_tx, 0); // confirm sending $loaded_txo = $txo_repository->findByTXIDAndOffset($txid, 0); PHPUnit::assertEquals(TXO::SENDING, $loaded_txo['type'], 'Unexpected type of ' . TXO::typeIntegerToString($loaded_txo['type'])); PHPUnit::assertTrue($loaded_txo['spent']); // receive unconfirmed transactions $loaded_txo = $txo_repository->findByTXIDAndOffset($sending_tx['txid'], 0); PHPUnit::assertEquals(0, $loaded_txo['n']); PHPUnit::assertEquals(TXO::UNCONFIRMED, $loaded_txo['type']); }
/** * Execute the console command. * * @return mixed */ public function fire() { $txo_repository = app('App\\Repositories\\TXORepository'); $payment_address_repo = app('App\\Repositories\\PaymentAddressRepository'); $bitcoin_payer = app('Tokenly\\BitcoinPayer\\BitcoinPayer'); $payment_address_uuid = $this->input->getArgument('payment-address-uuid'); $show_spent = $this->input->getOption('spent'); 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(); } $xchain_utxos_map = []; foreach ($payment_addresses as $payment_address) { // get xchain utxos $db_txos = $txo_repository->findByPaymentAddress($payment_address, null, $show_spent ? null : true); // all or unspent only foreach ($db_txos as $db_txo) { $xchain_utxos_map[$db_txo['txid'] . ':' . $db_txo['n']] = $db_txo; } } // build a table $bool = function ($val) { return $val ? '<info>true</info>' : '<comment>false</comment>'; }; $headers = ['address', 'txid', 'n', 'amount', 'type', 'spent', 'green', 'created']; $rows = []; foreach ($xchain_utxos_map as $identifier => $txo) { $address = $payment_address_repo->findById($txo['payment_address_id']); $pieces = explode('.', CurrencyUtil::satoshisToFormattedString($txo['amount'])); if (count($pieces) == 2) { $amount = $pieces[0] . "." . str_pad($pieces[1], 8, '0', STR_PAD_RIGHT); } else { $amount = $amount . ".00000000"; } $created = $txo['created_at']->setTimezone('America/Chicago')->format("Y-m-d h:i:s A"); $type = TXO::typeIntegerToString($txo['type']); $rows[] = [$address['address'], $txo['txid'], $txo['n'], $amount, $type, $bool($txo['spent']), $bool($txo['green']), $created]; } $this->table($headers, $rows); $this->info('done'); }
public function transferAccounts(TXO $model, Account $from, Account $to, $allowed_types = null) { if ($allowed_types === null) { $allowed_types = [TXO::UNCONFIRMED, TXO::CONFIRMED]; } return $model->where('id', '=', $model['id'])->where('account_id', '=', $from['id'])->whereIn('type', $allowed_types)->update(['account_id' => $to['id']]); }