protected function addressFromScriptHex($script_hex) { $address = null; try { $script = ScriptFactory::fromHex($script_hex); $classifier = new InputClassifier($script); if ($classifier->isPayToPublicKeyHash()) { $decoded = $script->getScriptParser()->decode(); $public_key = PublicKeyFactory::fromHex($decoded[1]->getData()); $address = $public_key->getAddress()->getAddress(); } else { if ($classifier->isPayToScriptHash()) { $decoded = $script->getScriptParser()->decode(); $hex_buffer = $decoded[count($decoded) - 1]->getData(); $sh_address = new ScriptHashAddress(ScriptFactory::fromHex($hex_buffer)->getScriptHash()); $address = $sh_address->getAddress(); } else { // unknown script type Log::debug("Unable to classify script " . substr($hex, 0, 20) . "..."); } } } catch (Exception $e) { Log::error("failed to get address from script. " . $e->getMessage()); } return $address; }
protected function generateComposedTransactionModel($request_id, PaymentAddress $payment_address, $destination, $float_quantity, $asset, $float_fee, $float_btc_dust_size, $is_sweep) { // check to see if this signed transaction already exists in the database $composed_transaction_model = $this->composed_transaction_repository->getComposedTransactionByRequestID($request_id); if ($composed_transaction_model === null) { // build the signed transactions $change_address_collection = null; $built_transaction_to_send = $this->buildSignedTransactionToSend($payment_address, $destination, $float_quantity, $asset, $change_address_collection, $float_fee, $float_btc_dust_size, $is_sweep); // get the utxo identifiers $utxo_identifiers = $this->buildUTXOIdentifiersFromUTXOs($built_transaction_to_send->getInputUtxos()); // store the signed transactions to the database cache $signed_transaction_hex = $built_transaction_to_send->getTransactionHex(); $txid = $built_transaction_to_send->getTxId(); $composed_transaction_model = $this->composed_transaction_repository->storeOrFetchComposedTransaction($request_id, $txid, $signed_transaction_hex, $utxo_identifiers); // mark each UTXO as spent $this->txo_repository->updateByTXOIdentifiers($utxo_identifiers, ['spent' => 1]); // create the new UTXOs that belong to any of our addresses $account = AccountHandler::getAccount($payment_address); $this->clearPaymentAddressInfoCache(); foreach ($built_transaction_to_send->getOutputUtxos() as $output_utxo) { if ($output_utxo['amount'] <= 0) { // don't store OP_RETURN UTXOs with no value continue; } // create new UTXO $utxo_destination_address = AddressFactory::fromOutputScript(ScriptFactory::fromHex($output_utxo['script']))->getAddress(); list($found_payment_address, $found_account) = $this->loadPaymentAddressInfo($utxo_destination_address); if ($found_payment_address) { $this->txo_repository->create($found_payment_address, $found_account, ['txid' => $output_utxo['txid'], 'n' => $output_utxo['n'], 'amount' => $output_utxo['amount'], 'script' => $output_utxo['script'], 'type' => TXO::UNCONFIRMED, 'spent' => 0, 'green' => 1]); } } } return $composed_transaction_model; }
<?php require_once "../vendor/autoload.php"; use BitWasp\Bitcoin\Script\ScriptFactory; $script = ScriptFactory::fromHex($argv[1]); print_r($script->getScriptParser()->getHumanReadable());
protected function addInputsAndReturnPreviousOutputs($utxos, $tx_builder) { $prev_transaction_outputs = []; foreach ($utxos as $utxo) { $script_instance = ScriptFactory::fromHex($utxo['script']); $tx_builder->input($utxo['txid'], $utxo['n'], $script_instance); $prev_transaction_output = new TransactionOutput($utxo['amount'] / self::SATOSHI, $script_instance); $prev_transaction_outputs[] = $prev_transaction_output; } return $prev_transaction_outputs; }
<?php require "../vendor/autoload.php"; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Transaction\TransactionFactory; $ecAdapter = Bitcoin::getEcAdapter(); $math = $ecAdapter->getMath(); $privHex1 = '421c76d77563afa1914846b010bd164f395bd34c2102e5e99e0cb9cf173c1d87'; $privHex2 = 'f7225388c1d69d57e6251c9fda50cbbf9e05131e5adb81e5aa0422402f048162'; $redeemScriptHex = '52410443f3ce7c4ddf438900a6662420511ea48321f8cedd3e63943700b07ac9752a6bf18230095730b18f2d3c3dbdc0a892ca62b1722730f183d370963d6f4d3e20c84104f260c8b554e9d0921c507fb231d0e226ba17462078825c56170facb6567dcec700750bd529f4361da21f59fbfc7d0bce319fdef4e7c524e82d3e313e92b1b34752ae'; $txid = '4141414141414141414141414141414141414141414141414141414141414141'; $vout = 0; $amount = '161662670'; $fee = '12345'; $amountAfterFee = $math->sub($amount, $fee); // Two users independently create private keys. $pk1 = \BitWasp\Bitcoin\Key\PrivateKeyFactory::fromHex($privHex1); $pk2 = \BitWasp\Bitcoin\Key\PrivateKeyFactory::fromHex($privHex2); $outpoint = new \BitWasp\Bitcoin\Transaction\OutPoint(\BitWasp\Buffertools\Buffer::hex($txid), $vout); $redeemScript = new \BitWasp\Bitcoin\Script\P2shScript(\BitWasp\Bitcoin\Script\ScriptFactory::fromHex($redeemScriptHex)); $os = $redeemScript->getOutputScript(); // One party (pk1) wants to spend funds. He creates a transaction spending the funding tx to his address. $spendTx = TransactionFactory::build()->spendOutPoint($outpoint)->payToAddress($amountAfterFee, $pk1->getAddress())->get(); // Two parties sign the transaction (can be done in steps) $signer = TransactionFactory::sign($spendTx); $signer->sign(0, $pk1, $os, $redeemScript)->sign(0, $pk2, $os, $redeemScript); $signed = $signer->get(); $fundTx = TransactionFactory::build()->input('4d7adb19fff03892a11924f2a9188e36dbbdf0f3bb341b6514475e4df238184b', 0)->output(1000000, $os)->get(); echo $fundTx->getHex() . "\n"; echo $fundTx->getTxId()->getHex() . "\n"; echo "Fully signed transaction: " . $signed->getHex() . "\n";