public function __construct()
 {
     parent::__construct(function () {
         $consensus = new ConsensusFactory(Bitcoin::getEcAdapter());
         $loop = LoopFactory::create();
         $context = new ZmqContext($loop);
         $control = $context->getSocket(\ZMQ::SOCKET_SUB);
         $control->connect('tcp://127.0.0.1:5594');
         $control->subscribe('control');
         $control->on('messages', function ($msg) use($loop) {
             if ($msg[1] == 'shutdown') {
                 $loop->stop();
             }
         });
         $results = $context->getSocket(\ZMQ::SOCKET_PUSH);
         $results->connect("tcp://127.0.0.1:5593");
         $workers = $context->getSocket(\ZMQ::SOCKET_PULL);
         $workers->connect('tcp://127.0.0.1:5592');
         $workers->on('message', function ($message) use($consensus, $results) {
             $details = json_decode($message, true);
             $txid = $details['txid'];
             $flags = $details['flags'];
             $vin = $details['vin'];
             $scriptPubKey = new Script(Buffer::hex($details['scriptPubKey']));
             $tx = TransactionFactory::fromHex($details['tx']);
             $results->send(json_encode(['txid' => $txid, 'vin' => $vin, 'result' => $consensus->getConsensus(new Flags($flags))->verify($tx, $scriptPubKey, $vin)]));
         });
         $loop->run();
         exit(0);
     });
 }
Beispiel #2
0
 public function __construct(LoopInterface $loop)
 {
     $context = new \React\ZMQ\Context($loop);
     $pusher = new Pusher();
     $workers = $context->getSocket(\ZMQ::SOCKET_PUSH);
     $workers->bind("tcp://127.0.0.1:5557");
     // Listen for work from the web
     $receiver = $context->getSocket(\ZMQ::SOCKET_PULL);
     $receiver->bind("tcp://127.0.0.1:5555");
     $receiver->on('message', function ($msg) use($workers) {
         // Create
         echo "Received: " . $msg . "\n";
         $workers->send($msg);
     });
     $control = $context->getSocket(\ZMQ::SOCKET_PULL);
     $control->bind('tcp://127.0.0.1:5510');
     $control->on('message', function ($msg) use($pusher) {
         echo "CONTROL MESSAGE\n";
         $arr = json_decode($msg, true);
         $slug = $arr['slug'];
         $req = $arr['req'];
         $pusher->send($slug, $arr['req']);
     });
     $listener = $context->getSocket(\ZMQ::SOCKET_PULL);
     $listener->bind('tcp://127.0.0.1:5559');
     $listener->on('message', function ($msg) use($pusher) {
         echo " + - - - - - - - - - + \n";
         echo "       RESULTS         \n";
         print_r($msg);
         $message = json_decode($msg, true);
         if ($message['command'] == 'client.gotRequest') {
             $pusher->onClientGotRequest($message['slug']);
         } else {
             if ($message['command'] == 'client.gotPayment') {
                 $pusher->onClientGotPayment($message['slug']);
             } else {
                 if ($message['command'] == 'tx.complete') {
                     try {
                         $request = Request::find(['slug' => $message['slug']]);
                         $transaction = TransactionFactory::fromHex($message['tx']);
                         Transaction::create(['transaction' => $message['tx'], 'request_id' => $request->id, 'txid' => $transaction->getTransactionId()]);
                         $pusher->onCompleteTx($message['slug'], $message['tx']);
                     } catch (\Exception $e) {
                         return;
                     }
                 } else {
                     if ($message['command'] == 'tx.partial') {
                         $pusher->onCompleteTx($message['slug'], $message['tx']);
                     }
                 }
             }
         }
         echo "\n + - - - - - - - - - + \n\n";
     });
     // Set up our WebSocket server for clients wanting real-time updates
     $webSock = new \React\Socket\Server($loop);
     $webSock->listen(8080, '0.0.0.0');
     // Binding to 0.0.0.0 means remotes can connect
     $webServer = new \Ratchet\Server\IoServer(new \Ratchet\Http\HttpServer(new \Ratchet\WebSocket\WsServer(new \Ratchet\Wamp\WampServer($pusher))), $webSock);
 }
 /**
  * @param $txid
  * @return \React\Promise\Promise
  */
 public function transactionGet($txid)
 {
     return $this->client->request('blockchain.transaction.get', [$txid])->then(function (Response $response) {
         return TransactionFactory::fromHex($response->getResult());
     });
 }
Beispiel #4
0
 /**
  * @param TransactionInterface $tx
  * @param array $inputs
  * @param array $privateKeys
  * @param int $sighash
  * @param NetworkInterface $network
  * @return \BitWasp\Bitcoin\Transaction\Transaction
  * @throws \Exception
  */
 public function signrawtransaction(TransactionInterface $tx, array $inputs = [], array $privateKeys = [], $sighash = SigHash::ALL, NetworkInterface $network = null)
 {
     $tx = $this->client->execute('signrawtransaction', [$tx->getHex(), $inputs, array_map(function (PrivateKeyInterface $privateKey) use($network) {
         return $privateKey->toWif($network);
     }, $privateKeys), $sighash]);
     $this->checkNotNull($tx);
     return TransactionFactory::fromHex($tx['hex']);
 }
<?php

require_once __DIR__ . "/../vendor/autoload.php";
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Transaction\TransactionFactory;
use BitWasp\Bitcoin\Address\AddressFactory;
use BitWasp\Bitcoin\Key\PrivateKeyFactory;
Bitcoin::setNetwork(\BitWasp\Bitcoin\Network\NetworkFactory::bitcoinTestnet());
$network = Bitcoin::getNetwork();
$ecAdapter = Bitcoin::getEcAdapter();
$privateKey = PrivateKeyFactory::fromHex('17a2209250b59f07a25b560aa09cb395a183eb260797c0396b82904f918518d5');
echo "[Key: " . $privateKey->toWif($network) . " Address " . $privateKey->getAddress()->getAddress($network) . "]\n";
$txHex = '010000000114a2856f5a2992a4ca0814be16a0ae79e2f88a6f53a20fcbcad5249165f56ee7010000006a47304402201e733603ac36239010e05ad229b4a18411d5507950f696db0771a5b7fe8e051202203c46da7e970e89cbbdfb4ee62fa775597a32e5029ab1d2a94f786999df2c2fd201210271127f11b833239aefd400b11d576e7cc48c6969c8e5f8e30b0f5ec0a514edf7feffffff02801a0600000000001976a914c4126d1b70f5667e492e3301c3aa8bf1031e21a888ac75a29d1d000000001976a9141ef8d6913c289890a5e9ec249fedde4440877d0288ac88540500';
$myTx = TransactionFactory::fromHex($txHex);
$spendOutput = 0;
$recipient = AddressFactory::fromString('n1b2a9rFvuU9wBgBaoWngNvvMxRV94ke3x');
echo "[Send to: " . $recipient->getAddress($network) . " \n";
echo "Generate a transaction spending the one above \n";
$spendTx = TransactionFactory::build()->spendOutputFrom($myTx, $spendOutput)->payToAddress(40000, $recipient)->get();
echo "Sign transaction\n";
$signer = TransactionFactory::sign($spendTx);
$signer->sign(0, $privateKey, $myTx->getOutput($spendOutput)->getScript());
echo "Generate transaction: \n";
$new = $signer->get();
echo $new->getHex() . "\n";
 /**
  * @return TransactionCollection
  */
 public function getTransactions()
 {
     return new TransactionCollection(array_map(function ($binTx) {
         return TransactionFactory::fromHex(bin2hex($binTx));
     }, $this->payment->getTransactionsList()));
 }
 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;
 }
Beispiel #8
0
 private function getTestTx()
 {
     $hex = '0100000014e3b8f4a75dd3a033744d8245148d5a8b734e6ebb157ac12d49e65d4f01f6c86c000000006c493046022100e8a2df24fd890121d8dd85c249b742d0585ec17d18b1bf97050e72eaaceb1580022100d7c37967048a617d7551c8249ea5e58cbf71a0508a6c459dd3a9dfefba3c592f0121030c51892ad8c9df7590c84bc2475576d6dc0815a5bf3ca37f1c58fe82e45d9ef5ffffffff0f1408fa2773334487d1d37e45cb399d049c7e46db3faadfcc204656bce57f5e000000006b483045022100cc339da0e9330b2375124a5fae678b130a4e5215310d85a1db2c7da32dd9633a02205fb02c932eab91733920bab341ad61097f2ff5dc73e46577ce3b70fd0e2ecc4b0121033fd9e31bd2bdc7029d6f1cca55655c4b484aca7fdea11547b37a4aeaf347e132ffffffff72a329f6d5cb92a3cd9e8aa252f0c683f28cb57e8884cfff42ffdddaca86f2e4000000006a473044022013f6b4e159ba9f88825746f9c7d1131cb14667a83d6b3871b5bab2a8f9f75759022024e29aa4bb7c7b994468c0a7a7add2bb180fc9a48b0187d2e06239b358cce8eb0121037cf462b312b1696f2654a21100a6a726238b91455d0f50f69526335d9022fdc5ffffffff49d1bb27b1027249326f3ad35a06b3c7fc9af2c0318caa02c1a90ae2e2a46cf8000000006c493046022100b6381612d4a5b1c75d57fdf93ce8fe39d4541a97af5cd312dbd91925cbd2037e022100a32954780c7d711059524f03ed78cf2e234554977a7e2139e7e7c6949835da660121025a4098ac03d3f706bfdaa795f80350aad15b5a6a578cee2991c16edae0255e76ffffffffc6b749366d13fca59f264b2714bc090660eb291361f23d79b6515f48f35dfd2c010000006b48304502205421f94ee54d829f921785860d4603b82caf8f3722f768e26970f4baa625c0dc022100f3c0cee26b1a98558386fbfcb568100582acc7bc8423e3402313298e0a3291520121026bff9f45e1645a6a67f70e80439d982d3d6dd0fe31258f93ae65161a14b54648ffffffff1f48a79c65634eb19c4a7eaca76a3f8f7c47b649cf54c8fbb5be6f87f6a42fa7010000006a47304402207907ec39e5ff6a85c5c0e5b8d7a81750e1e450e85839d87cdde4cfba405f6ee602205439aa642218bb676d2d2b9c0c63dd44395ad85fad2954ac1794bb4b35e134fc0121033fd9e31bd2bdc7029d6f1cca55655c4b484aca7fdea11547b37a4aeaf347e132ffffffff3a339577e45201a85797937aa44fe7a31f9240ba8a9169e46c32bbd82fbc2ae3000000006a473044022018e0dbfb5ee617fb7d1c28c672fb5428cbc1edb6ed8cc76bc68682432c4bfe450220187a7d4e7b2af69a8e7c7ebfd1b6f02143cf7a32c1041c01bc5324bcd97101880121033fd9e31bd2bdc7029d6f1cca55655c4b484aca7fdea11547b37a4aeaf347e132ffffffff7d0e4f252c644d051e35ee839abde736f26dd2046c7ca18711c759e3c86fb15a220000006a473044022004dfb719c5afca95db100f4e55fb4dd27f4f9faf1a6eff390d9bbdbf9b28fa4b02206dfd0d5f74b4c6d8424d44461c6a230fc174902d2be8d1792e029c3d67a1be9601210388da4b2db35387cf3bfc786453e8ca952b5386c95ce1b39e7ff5cf62cb7033fbfffffffff009c6f8a9b86d97989eaaacf3ada9f9428bae3a1a01339b85fa541680271c3a000000006b48304502203c17278401d3f7e6ab56597b6b88c783db5aa534897954e92a95732b5d714a860221008be28d72988a8ba69ff3889337468df0e83612e9cfbead9118fb8f4decfb3e93012102cda10f1505ff6a3613f6aa31becba07e44eddc25110ae083e360577556f0178dffffffff75068f094fd516d1658dac8c88ae027852a84423831b780925fb3d591a308227010000006b48304502203ce1a111748534bc601cc4a879f4097b098f7622d28a3da89ac7b90f3b29ee52022100b7de6a03241f6fea37179c3b2f68f45b69c963edc19dc0b3b0350bb8ffbd9063012102c64a6d411eef9f79890d317ad72329608be5f58f6757e1c5c6d4f21076345ddcfffffffffc844c99e1adab4677dda6b5def33ce549293a40d08da6a8c36fb9274c76ba43000000006c493046022100ee2b946560aced0633a5151f1fa5dd0249d68bef420e43e1f7edfd0e83619cfd022100a433121fb022efb69043310bd982a842e7f5be737069d3535962ecd78c4954070121033fd9e31bd2bdc7029d6f1cca55655c4b484aca7fdea11547b37a4aeaf347e132ffffffff32f65f550d4ef09e451303af1d2f9964b4f62e7b6562d5dbe23d4be89ae32e36010000006b483045022100bb4b1af8c22e51e9a3f71fb2cd883746e3812cbfd6a0695bbd22e53d573cb6f20220539e478519411e1d277a844810ab756004cc7755ff585cda7aa2c9d93ab4570b01210290a17b828f33417e7e3cb179bd50a621c8381964e6e239e91eacf3f414018770fffffffff6a6dafe0ae32f6c891de86c4aa12b318eeb89ca4d8792906ae03fd0db04c76f010000006b48304502203dfe2f1d58fdcab2f67f079c14a26c69e88718d38615d5de8230ee74c1e55d9e022100bc7651cf77f142366b502c65c59790a3d2cfa52852feab04212d3ea68e040be0012103214083806ce8aebf35544845c73f1e9d4dcad2fc6057e6cda963498f5420fef9ffffffff11c3e0e2a520bd829fab9b4311e603de79ce1304e1f28204334f79d1fd2c9138010000006b48304502206196ca600a02bf7fd210489e520b915b521dfa84a37bf56f2022aa8e89d62e6f022100949aabaafe92aaa8e207f0699a4745179fdc34a475d5c783785a58744ed5dd410121033fd9e31bd2bdc7029d6f1cca55655c4b484aca7fdea11547b37a4aeaf347e132ffffffff54dffe807c0b935528100313322949738717dc2af2f374f2a72af24b82291f70000000006b483045022100b84abff6f636082d2b85da4de25de13388a7901f0df5b87d871305e694667b4f0220477619c2140bc2d7dfab0d2b7d49f0729afb951831c7a64ee4bede7d8a46960b012102cda10f1505ff6a3613f6aa31becba07e44eddc25110ae083e360577556f0178dffffffff9923148b409a0888e42612e964216eb575b8fe4d0cfe5aad84323962c219373b000000006b483045022100cc88b67cce1655c38c60ada140b9c34343411cc309c45410edf2b4f133520c03022044c3554a294f6a412219b710689d67c5d8519fc6a139ee311985a14b8b55fd6f012102cda10f1505ff6a3613f6aa31becba07e44eddc25110ae083e360577556f0178dffffffff5bb09bbcbdd756af1f08457f7c1319aa67d5488f359b58e6f36920b808c789bb010000006a473044022051b255884c8f118780e394c054c5df12d813e3b9983a9854c89e7ffd015cbf5702200ed58fac38a91e19d755d30d910a04aa29848608b72f99aef68e0ecedcbdca53012103f57996ef25762717a75b6d75f0166a33f775783766513118b5476933d7af8078ffffffffc3c978e2e413506b75b7882cc38cf6f40d199c7226f73b5e4ab8295703fd4b03d50000006b48304502201a07c4ce0f76c4f5d96c45811bfa08c00483c987e1297324f40136a4c452c306022100d553873b6b3c20ae2b6a588704bae9daa5093b17283e0b196a27d6e4022ff8a50121032beebbe7e386f1fd27a9a3e59640deaa5f60835ab789012175c0f517149c77e3ffffffff3944343f32f93d43752bea7d916571e236295fbff53c7a9133d09f741116fac5000000006b483045022074aac638f77fed744feb1e99f4a71f20278686fc2f91264058facd9983cde9fb0221008250b8d62dbb8d3954517f9f80e236d1c74720723459b5d69656dadf781ee2e9012102cda10f1505ff6a3613f6aa31becba07e44eddc25110ae083e360577556f0178dffffffff781119976951dfc6f8a617077068fcb623475acef7eff09808a5ef3281a0ef70010000006b48304502200236e5c6b0787756449043fd413307c176be2b39fb7da11a18e10708a72877fe022100836b99f32532039e6326cbf282cbf78140c53883c474443bd6e6145e52dfb08d012103dd033367f07aee4f365a47cdf3c45147887492c6d20788970296d3b94eb1cfd8ffffffff1365487900000000001976a9143f6cd41f7caeda87b86bc9e009295f179612f45488acc7440f00000000001976a914df90390bee06889ed003b3c4d024a9fd211cf96788ace0ee4504000000001976a9141d8aa01e6628f333fd6fd9d3b88c3f761869caa488acd5080200000000001976a91412d24a8a61e1cd37825fd31bd61eebc2c32ad77688ac0842b582000000001976a9147fb7cccd54bf322ddae63b6b2e20a3624622091888acd5113916000000001976a914e75fa783b5b319578a53f2f18c37d88513d060b088ac80969800000000001976a9140ce8c479dad1b78baeea2217af17655b908b59b888ace8fb1204000000001976a9141a80a0ee9b4f1d03c3fb2220e4124d441431d41888ac00e1f505000000001976a914b1fdf35dd37a1a5359ad829f5f43760cd1ea61d588ac80626a94000000001976a9142a929cae46f0b4e5742ae38d6040f11a2b70e7d188ac109d0a02000000001976a914a4b5bfbe26ef9ac8d6e06738b50065b25f3dcce288acab110400000000001976a9146fbc4dd98c194853dc9a3e6f195bddad8eef609788ac00e1f505000000001976a914e1733c6b9e4c98f4ddc19370dd5cae0727af04e788ac5d44d502000000001976a9147514615f455bdfb8b9da74c7707ef0426606c33288ac404b4c00000000001976a914166e78015832ba760593bb292993391d4554a39a88acf0190b01000000001976a91409859ea62e00e0531873c135e37efbeca610d36788ace2fcae8f000000001976a914b40d92da29c478049a8d15bfd85b6ce230863df288acc07a3e22000000001976a9141e12d7845e76857bfba94079c1faca68b3ae24c088ac9e130e01000000001976a9144bdb0b7712726c2684461cd4e5b08934def0187c88ac00000000';
     $tx = TransactionFactory::fromHex($hex);
     return [$hex, $tx];
 }
Beispiel #9
0
require "vendor/autoload.php";
use React\EventLoop\Factory as LoopFactory;
use React\ZMQ\Context as ZmqContext;
use BitWasp\Bitcoin\Script\ScriptFactory;
use BitWasp\Bitcoin\Transaction\TransactionFactory;
use BitWasp\Bitcoin\Flags;
use BitWasp\Buffertools\Buffer;
use BitWasp\Bitcoin\Script\Script;
$loop = LoopFactory::create();
$context = new ZmqContext($loop);
$control = $context->getSocket(\ZMQ::SOCKET_SUB);
$control->connect('tcp://127.0.0.1:5594');
$control->subscribe('control');
$control->on('messages', function ($msg) use($loop) {
    if ($msg[1] == 'shutdown') {
        $loop->stop();
    }
});
$workers = $context->getSocket(\ZMQ::SOCKET_REP);
$workers->connect('tcp://127.0.0.1:5592');
$workers->on('message', function ($message) use($workers) {
    $details = json_decode($message, true);
    $txid = $details['txid'];
    $flags = $details['flags'];
    $vin = $details['vin'];
    $scriptPubKey = new Script(Buffer::hex($details['scriptPubKey']));
    $tx = TransactionFactory::fromHex($details['tx']);
    $workers->send(json_encode(['txid' => $txid, 'vin' => $vin, 'result' => ScriptFactory::consensus($flags)->verify($tx, $scriptPubKey, $vin, null)]));
});
$loop->run();
 public function testComposeP2SHSourceCounterpartyTransaction()
 {
     list($sender_address_1, $wif_key_1, $private_key_1) = $this->newAddressAndKey();
     list($sender_address_2, $wif_key_2, $private_key_2) = $this->newAddressAndKey();
     list($sender_address_3, $wif_key_3, $private_key_3) = $this->newAddressAndKey();
     // build a multisig address (2 of 3)
     $public_keys = [$private_key_1->getPublicKey(), $private_key_2->getPublicKey(), $private_key_3->getPublicKey()];
     $p2sh_script = ScriptFactory::p2sh()->multisig(2, $public_keys);
     $sender_address = $p2sh_script->getAddress()->getAddress();
     // variables
     $utxos = $this->fakeUTXOs($sender_address);
     $asset = 'SOUP';
     $quantity = 45;
     $destination = '1AAAA1111xxxxxxxxxxxxxxxxxxy43CZ9j';
     $fee = 0.0001;
     $btc_dust = 5.432E-5;
     // compose the send
     $composer = new Composer();
     $composed_unsigned_send = $composer->composeSend($asset, CryptoQuantity::fromFloat($quantity), $destination, null, $utxos, $sender_address, $fee, $btc_dust);
     list($txid, $unsigned_hex, $new_utxos) = $this->decomposeComposedTransaction($composed_unsigned_send);
     // parse the signed hex
     $transaction = TransactionFactory::fromHex($unsigned_hex);
     // check output 1
     $tx_output_0 = $transaction->getOutput(0);
     PHPUnit::assertEquals(intval(round($btc_dust * self::SATOSHI)), $tx_output_0->getValue());
     PHPUnit::assertEquals($destination, AddressFactory::fromOutputScript($tx_output_0->getScript())->getAddress());
     // check output 2
     $tx_output_1 = $transaction->getOutput(1);
     $op_return = $tx_output_1->getScript()->getScriptParser()->decode()[1]->getData()->getHex();
     $txid = $transaction->getInput(0)->getOutPoint()->getTxId()->getHex();
     $hex = $this->arc4decrypt($txid, $op_return);
     $expected_hex = '434e54525052545900000000000000000004fadf000000010c388d00';
     PHPUnit::assertEquals($expected_hex, $hex);
     // check output 3
     $tx_output_2 = $transaction->getOutput(2);
     PHPUnit::assertEquals(intval(round((0.123 + 0.0005 - $fee - $btc_dust) * self::SATOSHI)), $tx_output_2->getValue());
     PHPUnit::assertEquals($sender_address, AddressFactory::fromOutputScript($tx_output_2->getScript())->getAddress());
     // check $new_utxos
     PHPUnit::assertNotEmpty($new_utxos);
     PHPUnit::assertEquals(5432, $new_utxos[0]['amount']);
 }