public function validate($value, Constraint $constraint) { try { AddressFactory::fromString($value); } catch (\Exception $e) { $this->context->buildViolation($constraint->message)->addViolation(); } }
public function createSampleTXO($payment_address = null, $overrides = []) { if ($payment_address === null) { $payment_address = app('PaymentAddressHelper')->createSamplePaymentAddress(); } $account = AccountHandler::getAccount($payment_address, 'default'); // build a real script $script = ScriptFactory::scriptPubKey()->payToAddress(AddressFactory::fromString($payment_address['address'])); $attributes = array_merge(['txid' => $this->nextTXID(), 'n' => 0, 'script' => $script->getBuffer()->getHex(), 'amount' => 54321, 'type' => TXO::CONFIRMED, 'spent' => false, 'green' => false], $overrides); $txo_model = $this->txo_repository->create($payment_address, $account, $attributes); return $txo_model; }
/** * @param ScriptInterface $redeemScript */ public function __construct(ScriptInterface $redeemScript) { $classifier = ScriptFactory::scriptPubKey()->classify($redeemScript); if ($classifier->isPayToScriptHash()) { throw new \InvalidArgumentException('Provided script is a pay-to-script-hash output script'); } switch ($classifier->classify()) { case OutputClassifier::MULTISIG: $handler = new Multisig($redeemScript); break; case OutputClassifier::PAYTOPUBKEY: $handler = new PayToPubkey($redeemScript); break; case OutputClassifier::PAYTOPUBKEYHASH: $handler = new PayToPubkeyHash($redeemScript); break; default: throw new \InvalidArgumentException('redeemScript not yet supported'); } $this->redeemScript = $redeemScript; $this->outputScript = ScriptFactory::scriptPubKey()->payToScriptHash($redeemScript); $this->p2shAddress = AddressFactory::fromScript($redeemScript); $this->handler = $handler; }
<?php require "../vendor/autoload.php"; use BitWasp\Bitcoin\Address\AddressFactory; use BitWasp\Bitcoin\Transaction\TransactionFactory; $transaction = TransactionFactory::build()->input('99fe5212e4e52e2d7b35ec0098ae37881a7adaf889a7d46683d3fbb473234c28', 0)->payToAddress(29890000, AddressFactory::fromString('19SokJG7fgk8iTjemJ2obfMj14FM16nqzj'))->payToAddress(100000, AddressFactory::fromString('1CzcTWMAgBNdU7K8Bjj6s6ezm2dAQfUU9a'))->get(); echo $transaction->getHex() . PHP_EOL;
$url = urlencode($app->url('request.request', ['slug' => $request->slug])); $bitcoinUrl = "bitcoin:" . $requirements[0]->address . "?amount=" . $request->valuebtc . "&r=" . $url; //$bitcoinUrl = "bitcoin:?r=" . $url; //echo $bitcoinUrl . "\n"; return $app['twig']->render('info.html.twig', ['request' => $request->to_array(), 'requirements' => $reqs, 'address' => $reqs[0]['address'], 'url' => $url, 'bitcoinUrl' => $bitcoinUrl]); })->bind('info'); $app->match('/new', function (\Symfony\Component\HttpFoundation\Request $request) use($app) { // some default data for when the form is displayed the first time /** @var \Symfony\Component\Form\FormFactory $factory */ $factory = $app['form.factory']; $form = $factory->createBuilder()->add('address', 'text', array('attr' => array('class' => 'form-control', 'placeholder' => 'Bitcoin address'), 'constraints' => [new \Symfony\Component\Validator\Constraints\NotBlank(), new \BitWasp\Payments\Application\Validator\BitcoinAddress()]))->add('value', 'text', array('attr' => array('class' => 'form-control', 'placeholder' => 'Amount in satoshis'), 'constraints' => new \Symfony\Component\Validator\Constraints\NotBlank()))->add('send', 'submit', array('attr' => array('class' => 'btn btn-lg btn-primary btn-block')))->getForm(); if ('POST' == $request->getMethod()) { $form->bind($request); if ($form->isValid()) { $data = $form->getData(); $address = \BitWasp\Bitcoin\Address\AddressFactory::fromString($data['address']); $script = \BitWasp\Bitcoin\Script\ScriptFactory::scriptPubKey()->payToAddress($address); $txOut = new \BitWasp\Bitcoin\Transaction\TransactionOutput($data['value'], $script); $slug = bin2hex(openssl_random_pseudo_bytes(32)); $signer = new \BitWasp\Bitcoin\PaymentProtocol\PaymentRequestSigner('none'); $builder = new \BitWasp\Bitcoin\PaymentProtocol\PaymentRequestBuilder($signer, 'main', time()); $builder->addOutput($txOut); $details = $builder->getPaymentDetails(); $details->setPaymentUrl($app->url('request.payment', ['slug' => $slug])); $request = $builder->getPaymentRequest(); $totalValue = $data['value']; $amount = new \BitWasp\Bitcoin\Amount(); $dbRequest = \BitWasp\Payments\Db\Request::create(['slug' => $slug, 'value' => $totalValue, 'valueBtc' => $amount->toBtc($data['value']), 'payment_request' => $request->serialize()]); $output = \BitWasp\Payments\Db\OutputRequirement::create(['request_id' => $dbRequest->id, 'value' => $data['value'], 'valueBtc' => $amount->toBtc($data['value']), 'address' => $data['address'], 'script' => $txOut->getScript()->getBinary()]); $app['request_api']->pushRequest($slug, [$output]); return $app->redirect($app['url_generator']->generate('info', array('slug' => $dbRequest->slug)));
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; }
$network = Bitcoin::getNetwork(); $ecAdapter = Bitcoin::getEcAdapter(); $bitcoind = RpcFactory::bitcoind($host, $port, $user, $pass); $privateKey1 = PrivateKeyFactory::fromHex('17a2209250b59f07a25b560aa09cb395a183eb260797c0396b82904f918518d5', true); $privateKey2 = PrivateKeyFactory::fromHex('17a2209250b59f07a25b560aa09cb395a183eb260797c0396b82904f918518d6', true); $redeemScript = ScriptFactory::multisig(2, array($privateKey1->getPublicKey(), $privateKey2->getPublicKey())); $multisig = $redeemScript->getAddress(); echo "[P2SH address: " . $multisig->getAddress($network) . " ]\n"; echo "[private key order: " . implode(", ", array_map(function (PublicKeyInterface $publicKey) use($privateKey1, $privateKey2) { if ($publicKey->getBinary() == $privateKey1->getPublicKey()->getBinary()) { return "1"; } else { return "2"; } }, $redeemScript->getKeys())) . "]\n"; $myTx = $bitcoind->getrawtransaction('6d4f5d2cce43660c29e03a794497da3f204312358ca6a6e47035ef916ce19db9', true); $spendOutput = 0; $recipient = AddressFactory::fromString('n1b2a9rFvuU9wBgBaoWngNvvMxRV94ke3x'); echo "[Send to: " . $recipient->getAddress($network) . " \n"; // Prep work - importing from a tx will only bring container to contents of $new - no metadata $new = new \BitWasp\Bitcoin\Transaction\TransactionBuilder($ecAdapter); $new->spendOutput($myTx, $spendOutput)->payToAddress($recipient, 100000); // Start doing things which require state tracking $new->signInputWithKey($privateKey1, $redeemScript->getOutputScript(), $spendOutput, $redeemScript)->signInputWithKey($privateKey2, $redeemScript->getOutputScript(), $spendOutput, $redeemScript); $tx = $new->getTransaction(); // Send transaction to multisig address try { $txid = $bitcoind->sendrawtransaction($tx, true); } catch (\Exception $e) { echo "\n\nException: (" . $e->getCode() . ") " . $e->getMessage() . "\n"; }
<?php require "../vendor/autoload.php"; use BitWasp\Bitcoin\Address\AddressFactory; use BitWasp\Bitcoin\PaymentProtocol\PaymentRequestBuilder; use BitWasp\Bitcoin\PaymentProtocol\PaymentRequestSigner; $time = time(); $amount = 10000; $destination = '18Ffckz8jsjU7YbhP9P44JMd33Hdkkojtc'; $paymentUrl = 'http://192.168.0.223:81/bitcoin-php/examples/bip70.fetch.php?time=' . $time; // Create a signer for x509+sha256 - this requires a readable private key and certificate chain. // $signer = new PaymentRequestSigner('none'); $signer = new PaymentRequestSigner('x509+sha256', '/var/www/git/paymentrequestold/.keys/ssl.key', '/var/www/git/paymentrequestold/.keys/ssl.pem'); $builder = new PaymentRequestBuilder($signer, 'main', time()); // PaymentRequests contain outputs that the wallet will fulfill $address = AddressFactory::fromString($destination); $builder->addAddressPayment($address, $amount); // Create the request, write it to a temporary file $request = $builder->getPaymentRequest(); // Create a url + display a QR $encodedUrl = urlencode($paymentUrl); $uri = "bitcoin:{$address}?r={$encodedUrl}&amount=0.00010000"; $qr = urlencode($uri); echo "<a href='{$uri}'>Pay<img src='https://chart.googleapis.com/chart?chs=300x300&cht=qr&chl={$qr}'></a>";
/** * @return \BitWasp\Bitcoin\Address\ScriptHashAddress */ public function getAddress() { return AddressFactory::fromScript($this->getRedeemScript()); }
$network = Bitcoin::getNetwork(); $ecAdapter = Bitcoin::getEcAdapter(); $host = '127.0.0.1'; $port = '18332'; $user = getenv('BITCOINLIB_RPC_USER') ?: 'bitcoinrpc'; $pass = getenv('BITCOINLIB_RPC_PASSWORD') ?: 'BBpsLqmCCx7Vp8sRd5ygDxFkHZBgWLTTi55QwWgN6Ng6'; Bitcoin::setNetwork(\BitWasp\Bitcoin\Network\NetworkFactory::bitcoinTestnet()); $bitcoind = RpcFactory::bitcoind($host, $port, $user, $pass); // Address to fund this test $fundsKey = PrivateKeyFactory::fromWif('cQTqzY1hhC8u4aeFmqodENTnJvxgSk316PakYVgcFaHqAa4aCpwW'); $address = $fundsKey->getAddress()->getAddress(); // Txid / spendable output of funding transaction, funds will be moved from here -> multisig $myTx = $bitcoind->getrawtransaction('e76ef5659124d5cacb0fa2536f8af8e279aea016be1408caa492295a6f85a214', true); $spendOutput = 0; // Funds will be send from Multisig -> this $recipient = \BitWasp\Bitcoin\Address\AddressFactory::fromString('n1b2a9rFvuU9wBgBaoWngNvvMxRV94ke3x'); // Begin $privateKey1 = PrivateKeyFactory::fromHex('17a2209250b59f07a25b560aa09cb395a183eb260797c0396b82904f918518d5', true); $privateKey2 = PrivateKeyFactory::fromHex('17a2209250b59f07a25b560aa09cb395a183eb260797c0396b82904f918518d6', true); $redeemScript = ScriptFactory::multisig(2, array($privateKey1->getPublicKey(), $privateKey2->getPublicKey())); // First, move money from fundsKey to the multisig address $new = new \BitWasp\Bitcoin\Transaction\TransactionBuilder($ecAdapter); $new->spendOutput($myTx, $spendOutput)->payToAddress($redeemScript->getAddress(), 200000); echo "[Fund this address: {$address}]\n"; echo "[P2SH address: " . $redeemScript->getAddress() . " ]\n"; $new->signInputWithKey($fundsKey, $myTx->getOutputs()->getOutput($spendOutput)->getScript(), 0); $tx = $new->getTransaction(); try { echo "try sending to multisig address\n"; echo $tx->getHex() . "\n"; $txid = $bitcoind->sendrawtransaction($tx, true);
public function parseBTCTransaction($raw_transaction_hex, $is_counterparty = false) { if (!$raw_transaction_hex) { throw new Exception("Transaction hex was empty", 1); } $transaction = TransactionFactory::fromHex($raw_transaction_hex); $out = []; // inputs $inputs = $transaction->getInputs(); $out['inputs'] = []; foreach ($inputs as $input) { // build the ASM $asm = ""; $opcodes = $input->getScript()->getOpCodes(); foreach ($input->getScript()->getScriptParser()->decode() as $op) { // $asm .= $opcodes->getOp($op->getOp()); if ($op->isPush()) { $item = $op->getData()->getHex(); } else { $item = $opcodes->getOp($op->getOp()); } $asm = ltrim($asm . " " . $item); } // extract the address $address = null; // address decoding not implemented yet // $classifier = new InputClassifier($script); // if ($classifier->isPayToPublicKeyHash()) { // $decoded = $script->getScriptParser()->decode(); // $hex_buffer = $decoded[1]->getData(); // $public_key = PublicKeyFactory::fromHex($hex_buffer); // $address = $public_key->getAddress()->getAddress(); // } else if ($classifier->isPayToScriptHash()) { // $decoded = $script->getScriptParser()->decode(); // $hex_buffer = $decoded[count($decoded)-1]->getData(); // $script = ScriptFactory::fromHex($hex_buffer); // $sh_address = new ScriptHashAddress($script->getScriptHash()); // $address = $sh_address->getAddress(); // } $out['inputs'][] = ['txid' => $input->getTransactionId(), 'n' => $input->getVout(), 'asm' => $asm]; } // txid $out['txid'] = $transaction->getTxId()->getHex(); // destination $output_offset = 0; $outputs = $transaction->getOutputs(); $destination = AddressFactory::getAssociatedAddress($outputs[$output_offset]->getScript()); $out['destination'] = $destination; $out['btc_amount'] = $outputs[0]->getValue(); if ($is_counterparty) { // OP_RETURN ++$output_offset; $obfuscated_op_return_hex = $outputs[$output_offset]->getScript()->getScriptParser()->decode()[1]->getData()->getHex(); $hex = $this->arc4decrypt($transaction->getInput(0)->getTransactionId(), $obfuscated_op_return_hex); $counterparty_data = $this->parseTransactionData(hex2bin(substr($hex, 16))); $out = $counterparty_data + $out; $out['btc_dust_size'] = $outputs[0]->getValue(); } // change ++$output_offset; $change = []; for ($i = $output_offset; $i < count($outputs); $i++) { $output = $outputs[$i]; $change[] = [AddressFactory::getAssociatedAddress($outputs[$i]->getScript()), $output->getValue()]; } $out['change'] = $change; // sum all outputs $sum_out = 0; foreach ($outputs as $output) { $sum_out += $output->getValue(); } $out['sum_out'] = $sum_out; return $out; }
if ($debug) { echo "[Key: " . $privateKey->toWif($network) . "]\n"; echo "[Address " . $privateKey->getAddress()->getAddress($network) . "]\n"; } // In order to run the sample you will need: // 1.- Use the faucet to fund source address // Faucet https://accounts.blockcypher.com/testnet-faucet?a=n3D2YXwvpoPg8FhcWpzJiS3SvKKGD8AXZ4 // 2.- Get unspent transaction outputs (UTXOs) and select one: // https://api.blockcypher.com/v1/btc/test3/addrs/n3D2YXwvpoPg8FhcWpzJiS3SvKKGD8AXZ4?unspentOnly=true // 3.- Get the hex tx for the selected UTXO: // https://live.blockcypher.com/btc-testnet/tx/e7f034f4a56999d04d8a3a8f07dca10e87cd4a7fd2a779e9ecd41c57afec84f8/ // 4.- Copy Tx Hex and paste here: $txHex = '0100000001b674eafd9c1a79402661e7e7b37746145869260c29263f213f6f120ea8a95574010000006b483045022100ac406c14ef2da774d64d5504340fd278a827a99941cf0bef26fdff17c191ffa4022016a69a281ec1fcdf22c34543ff97a5c332ed12856fb44e525cf8ba3aea7c2d4101210274cb62e999bdf96c9b4ef8a2b44c1ac54d9de879e2ee666fdbbf0e1a03090cdfffffffff02e8030000000000001976a914a93806b8ae200fffca565f7cf9ef3ab17d4ffe8888ac204e0000000000001976a914edeed3ce7f485e44bc33969af08ec9250510f83f88ac00000000'; $myTx = TransactionFactory::fromHex($txHex); $spendOutput = 0; $recipient = AddressFactory::fromString('mvwhcFDFjmbDWCwVJ73b8DcG6bso3CZXDj'); if ($debug) { echo "[Send to: " . $recipient->getAddress($network) . "]\n"; } $builder = new TransactionBuilder($ecAdapter); $builder->spendOutput($myTx, $spendOutput)->payToAddress($recipient, 1000); if ($debug) { echo "Setup stage\n"; //print_r($builder); echo "Signing\n"; } // This line throws a warning but it works: // https://github.com/mdanter/phpecc/issues/90 error_reporting(E_ERROR | E_PARSE); $builder->signInputWithKey($privateKey, $myTx->getOutputs()->getOutput($spendOutput)->getScript(), 0); if ($debug) {
protected function payChange($change_amounts, $tx_builder) { if ($change_amounts) { foreach ($change_amounts as $change_amount_pair) { $address = $change_amount_pair[0]; $btc_satoshis = $change_amount_pair[1]; $tx_builder->payToAddress($btc_satoshis, AddressFactory::fromString($address)); } } }
/** * @return \BitWasp\Bitcoin\Address\PayToPubKeyHashAddress */ public function getAddress() { $address = AddressFactory::fromKey($this); return $address; }
} else { $vout_id = $db->insert($voSql, $voFlds); } } else { $voSql = "update transactions_vouts set transaction_id = ?, txid = ?, " . "value = ?, n = ?, reqSigs = ?, type = ?, hexgz = ? where vout_id = ?"; $voFlds[0] = $voFlds[0] . 'i'; $voFlds[] = $vout_id; if ($outputType == 'sketchy') { $voFlds[count($voFlds) - 2] = ""; $db->update($voSql, $voFlds); } else { $db->update($voSql, $voFlds); } } if ($outputType !== 'sketchy') { $address = AddressFactory::getAssociatedAddress($output->getScript(), $network); //echo $address,"\n"; $address_id = getAddressId($address); $aisql = "insert into transactions_vouts_addresses (vout_id, address_id) values (?, ?)"; $db->insert($aisql, ['ii', $vout_id, $address_id]); } } /* * * inputs * */ $inputs = $tx->getInputs(); for ($i = 0; $i < $inputs->count(); $i++) { $input = $inputs->getInput($i); $inputVout = $input->getVout();
<?php require "../vendor/autoload.php"; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\MessageSigner\MessageSigner; use BitWasp\Bitcoin\Serializer\MessageSigner\SignedMessageSerializer; use BitWasp\Bitcoin\Serializer\Signature\CompactSignatureSerializer; Bitcoin::setNetwork(\BitWasp\Bitcoin\Network\NetworkFactory::bitcoinTestnet()); $address = 'n2Z2DFCxG6vktyX1MFkKAQPQFsrmniGKj5'; $sig = '-----BEGIN BITCOIN SIGNED MESSAGE----- hi -----BEGIN SIGNATURE----- IBpGR29vEbbl4kmpK0fcDsT75GPeH2dg5O199D3iIkS3VcDoQahJMGJEDozXot8JGULWjN9Llq79aF+FogOoz/M= -----END BITCOIN SIGNED MESSAGE-----'; $ec = Bitcoin::getEcAdapter(); $addr = \BitWasp\Bitcoin\Address\AddressFactory::fromString($address); $serializer = new SignedMessageSerializer(new CompactSignatureSerializer(Bitcoin::getMath())); $signedMessage = $serializer->parse($sig); $signer = new MessageSigner($ec); if ($signer->verify($signedMessage, $addr)) { echo "Signature verified!\n"; } else { echo "Failed to verify signature!\n"; }
<?php require "../vendor/autoload.php"; require "../db/bootstrap.php"; $address = \BitWasp\Bitcoin\Address\AddressFactory::fromString('1J7jgWATD4Vfe9eUs7EL4YdadbPaM7cGgj'); $script = \BitWasp\Bitcoin\Script\ScriptFactory::scriptPubKey()->payToAddress($address); /** @var \BitWasp\Bitcoin\Transaction\TransactionOutputInterface[] $outputs */ $outputs = [new \BitWasp\Bitcoin\Transaction\TransactionOutput(1000000, $script)]; $signer = new \BitWasp\Bitcoin\PaymentProtocol\PaymentRequestSigner('none'); $builder = new \BitWasp\Bitcoin\PaymentProtocol\PaymentRequestBuilder($signer, 'main', time()); foreach ($outputs as $output) { $builder->addOutput($output); } $request = $builder->getPaymentRequest(); $value = 1000000; $amount = new \BitWasp\Bitcoin\Amount(); $list = \BitWasp\Payments\Db\Request::create(['slug' => bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)), 'value' => $value, 'valueBtc' => $amount->toBtc($value), 'payment_request' => $request->serialize()]); $req = []; foreach ($outputs as $output) { $req[] = \BitWasp\Payments\Db\OutputRequirement::create(['request_id' => $list->id, 'value' => $output->getValue(), 'valueBtc' => $amount->toBtc($value), 'script' => $output->getScript()->getBinary(), 'address' => $address->getAddress()]); }
/** * @return \BitWasp\Bitcoin\Address\ScriptHashAddress */ public function getAddress() { return AddressFactory::fromScript($this); }
protected function buildFakeUTXO($destination, $amount, $txid_number, $n) { $tx = TransactionFactory::build()->input('deadbeef00000000000000000000000000000000000000000000000000' . sprintf('%06d', $txid_number), $n)->payToAddress(intval(round($amount * self::SATOSHI)), AddressFactory::fromString($destination))->get(); $script = $tx->getOutput(0)->getScript(); return ['txid' => $tx->getTxId()->getHex(), 'n' => $n, 'amount' => intval(round($amount * self::SATOSHI)), 'script' => $script->getHex()]; }