/** * @param int $m * @param PublicKeyInterface[] $keys * @param bool|true $sort * @return ScriptCreator|Script */ public function multisig($m, array $keys = [], $sort = true) { $n = count($keys); if ($m > $n) { throw new \LogicException('Required number of sigs exceeds number of public keys'); } if ($n > 16) { throw new \LogicException('Number of public keys is greater than 16'); } if ($sort) { $keys = Buffertools::sort($keys); } $opM = \BitWasp\Bitcoin\Script\encodeOpN($m); $opN = \BitWasp\Bitcoin\Script\encodeOpN($n); $script = ScriptFactory::create(); foreach ($keys as $key) { if (!$key instanceof PublicKeyInterface) { throw new \LogicException('Values in $keys[] must be a PublicKey'); } $script->push($key->getBuffer()); } $keyBuf = $script->getScript()->getBuffer(); $script = new Script(new Buffer(chr($opM) . $keyBuf->getBinary() . chr($opN) . chr(Opcodes::OP_CHECKMULTISIG))); return $script; }
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; }
/** * @param EcAdapterInterface $ecAdapter * @param ScriptInterface $outputScript * @param ScriptInterface $redeemScript */ public function __construct(EcAdapterInterface $ecAdapter, ScriptInterface $outputScript, ScriptInterface $redeemScript = null) { /* $classifier = new OutputClassifier($outputScript); $this->scriptType = $this->prevOutType = $classifier->classify(); // Get the handler for this script type, and reclassify p2sh if ($this->scriptType === OutputClassifier::PAYTOSCRIPTHASH) { if (null === $redeemScript) { throw new \InvalidArgumentException('Redeem script is required when output is P2SH'); } $handler = new ScriptHash($redeemScript); $this->scriptType = $handler->classification(); } else { $handler = ScriptFactory::info($outputScript); } */ $handler = ScriptFactory::info($outputScript, $redeemScript); $this->scriptType = $this->prevOutType = $handler->classification(); if ($handler instanceof ScriptHash) { $this->scriptType = $handler->getInfo()->classification(); } // Gather public keys from redeemScript / outputScript $this->ecAdapter = $ecAdapter; $this->redeemScript = $redeemScript; $this->prevOutScript = $outputScript; $this->scriptInfo = $handler; // According to scriptType, extract public keys $this->publicKeys = $this->scriptInfo->getKeys(); }
/** * @param TransactionSignatureInterface[] $signatures * @param PublicKeyInterface[] $publicKeys * @return Script|ScriptInterface */ public function makeScriptSig(array $signatures = [], array $publicKeys = []) { $newScript = new Script(); if (count($signatures) === $this->getRequiredSigCount()) { $newScript = ScriptFactory::sequence([$signatures[0]->getBuffer()]); } return $newScript; }
/** * ScriptValidation constructor. * @param bool $active * @param int $flags */ public function __construct($active = true, $flags = InterpreterInterface::VERIFY_NONE) { if (!is_bool($active)) { throw new \InvalidArgumentException('ScriptValidationState: $active should be bool'); } $this->active = $active; $this->consensus = ScriptFactory::consensus($flags); }
/** * @param array $signatures * @param array $publicKeys * @return Script|ScriptInterface */ public function makeScriptSig(array $signatures = [], array $publicKeys = []) { $newScript = new Script(); if (count($publicKeys) > 0 && count($signatures) === $this->getRequiredSigCount()) { $newScript = ScriptFactory::scriptSig()->payToPubKeyHash($signatures[0], $publicKeys[0]); } return $newScript; }
/** * @return \BitWasp\Bitcoin\Block\BlockInterface */ public function getGenesisBlock() { $timestamp = new Buffer('The Times 03/Jan/2009 Chancellor on brink of second bailout for banks', null, $this->math); $publicKey = Buffer::hex('04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f', null, $this->math); $inputScript = ScriptFactory::sequence([Buffer::int('486604799', 4, $this->math)->flip(), Buffer::int('4', null, $this->math), $timestamp]); $outputScript = ScriptFactory::sequence([$publicKey, Opcodes::OP_CHECKSIG]); return new Block($this->math, $this->getGenesisBlockHeader(), new TransactionCollection([(new TxBuilder())->version('1')->input(new Buffer('', 32), 4294967295.0, $inputScript)->output(5000000000.0, $outputScript)->locktime(0)->get()])); }
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 UtxoView $view * @param TransactionInterface $tx * @return int */ public function getP2shSigOps(UtxoView $view, TransactionInterface $tx) { if ($tx->isCoinbase()) { return 0; } $nSigOps = 0; $scriptPubKey = ScriptFactory::scriptPubKey(); for ($i = 0, $c = count($tx->getInputs()); $i < $c; $i++) { $input = $tx->getInput($i); $outputScript = $view->fetchByInput($input)->getOutput()->getScript(); if ($scriptPubKey->classify($outputScript)->isPayToScriptHash()) { $nSigOps += $outputScript->countP2shSigOps($input->getScript()); } } return $nSigOps; }
/** * TxSignerContext constructor. * @param EcAdapterInterface $ecAdapter * @param ScriptInterface $outputScript * @param ScriptInterface|null $redeemScript */ public function __construct(EcAdapterInterface $ecAdapter, ScriptInterface $outputScript, ScriptInterface $redeemScript = null) { $handler = ScriptFactory::info($outputScript, $redeemScript); $handler->getKeys(); $this->scriptType = $this->prevOutType = $handler->classification(); if ($handler instanceof ScriptHash) { $this->scriptType = $handler->getInfo()->classification(); } // Gather public keys from redeemScript / outputScript $this->ecAdapter = $ecAdapter; $this->redeemScript = $redeemScript; $this->prevOutScript = $outputScript; $this->scriptInfo = $handler; // According to scriptType, extract public keys $this->publicKeys = $this->scriptInfo->getKeys(); }
/** * @param ScriptInterface $script * @param ScriptInterface|null $redeemScript * @return \BitWasp\Bitcoin\Script\ScriptInfo\ScriptInfoInterface */ public function load(ScriptInterface $script, ScriptInterface $redeemScript = null) { $classifier = ScriptFactory::scriptPubKey()->classify($script); if ($classifier->isPayToScriptHash()) { if (null === $redeemScript) { throw new \InvalidArgumentException('Redeem script is required when output is P2SH'); } $handler = new ScriptHash($redeemScript); } elseif ($classifier->isMultisig()) { $handler = new Multisig($script); } elseif ($classifier->isPayToPublicKey()) { $handler = new PayToPubkey($script); } elseif ($classifier->isPayToPublicKeyHash()) { $handler = new PayToPubkeyHash($script); } else { throw new \InvalidArgumentException('Unparsable script type'); } return $handler; }
/** * @param int|string $m * @param string $path * @param array $keys * @param HierarchicalKeySequence $sequences * @param bool $sort */ public function __construct($m, $path, array $keys, HierarchicalKeySequence $sequences, $sort = false) { if (count($keys) < 1) { throw new \RuntimeException('Must have at least one HierarchicalKey for Multisig HD Script'); } // Sort here to guarantee calls to getKeys() returns keys in the same order as the redeemScript. if ($sort) { $keys = $this->sortHierarchicalKeys($keys); } foreach ($keys as $key) { $this->keys[] = $key; } $this->m = $m; $this->path = $path; $this->sort = $sort; $this->sequences = $sequences; $this->redeemScript = ScriptFactory::p2sh()->multisig($m, array_map(function (HierarchicalKey $key) { return $key->getPublicKey(); }, $this->keys)); }
<?php require "../vendor/autoload.php"; use BitWasp\Buffertools\Buffer; use BitWasp\Bitcoin\Key\PrivateKeyFactory; use BitWasp\Bitcoin\Script\ScriptFactory; use BitWasp\Bitcoin\Transaction\OutPoint; use BitWasp\Bitcoin\Transaction\TransactionFactory; use BitWasp\Bitcoin\Script\WitnessProgram; use BitWasp\Bitcoin\Bitcoin; $wif = 'QP3p9tRpTGTefG4a8jKoktSWC7Um8qzvt8wGKMxwWyW3KTNxMxN7'; $s = \BitWasp\Bitcoin\Network\NetworkFactory::bitcoinSegnet(); Bitcoin::setNetwork($s); $ec = \BitWasp\Bitcoin\Bitcoin::getEcAdapter(); $key = PrivateKeyFactory::fromWif($wif); echo $key->getPublicKey()->getAddress()->getAddress() . PHP_EOL; $outpoint = new OutPoint(Buffer::hex('703f50920bff10e1622117af81b622d8bbd625460e61909cc3f8b8ee78a59c0d', 32), 0); $scriptPubKey = ScriptFactory::scriptPubKey()->payToPubKeyHash($key->getPublicKey()); $value = 100000000; $txOut = new \BitWasp\Bitcoin\Transaction\TransactionOutput($value, $scriptPubKey); $destination = new WitnessProgram(0, $key->getPubKeyHash()); $p2sh = new \BitWasp\Bitcoin\Script\P2shScript($destination->getScript()); $tx = TransactionFactory::build()->spendOutPoint($outpoint)->output(95590000, $p2sh->getOutputScript())->get(); $signed = new \BitWasp\Bitcoin\Transaction\Factory\Signer($tx, $ec); $signed->sign(0, $key, $txOut); $ss = $signed->get(); echo $ss->getHex() . PHP_EOL;
/** * @param ScriptInterface $inputScript * @param ScriptInterface $redeemScript * @return ScriptInterface */ public function payToScriptHash(ScriptInterface $inputScript, ScriptInterface $redeemScript) { return ScriptFactory::create($inputScript->getBuffer())->push($redeemScript->getBuffer())->getScript(); }
/** * @param AddressInterface $address * @param NetworkInterface $network * @return \React\Promise\Promise */ public function addressListUnspent(AddressInterface $address, NetworkInterface $network = null) { return $this->client->request('blockchain.address.listunspent', [$address->getAddress($network)])->then(function (Response $response) use($address) { return array_map(function (array $value) use($address) { return new Utxo($value['tx_hash'], $value['tx_pos'], new TransactionOutput($value['value'], ScriptFactory::scriptPubKey()->payToAddress($address))); }, $response->getResult()); }); }
/** * Create an output paying $value to an Address. * * @param AddressInterface $address * @param $value * @return $this */ public function payToAddress(AddressInterface $address, $value) { // Create Script from address, then create an output. $this->addOutput(new TransactionOutput($value, ScriptFactory::scriptPubKey()->payToAddress($address))); return $this; }
/** * @param TransactionInterface $tx * @return Transaction */ public function fixTransaction(Peer $sender, TransactionInterface $tx, &$wasMalleated = false) { $c = count($tx->getInputs()); $new = new TransactionInputCollection(); for ($i = 0; $i < $c; $i++) { $input = $tx->getInput($i); $script = $input->getScript(); $classify = ScriptFactory::scriptSig()->classify($input->getScript()); $this->inputs++; if ($classify->isPayToPublicKeyHash()) { $parsed = $input->getScript()->getScriptParser()->parse(); $txSig = TransactionSignatureFactory::fromHex($parsed[0]); $txSig = $this->fixSig($sender, $txSig, $wasMalleated); $script = ScriptFactory::create()->push($txSig->getBuffer())->push($parsed[1])->getScript(); } $new->addInput(new TransactionInput($input->getTransactionId(), $input->getVout(), $script, $input->getSequence())); } return new Transaction($tx->getVersion(), $new, $tx->getOutputs(), $tx->getLockTime()); }
/** * @return ScriptInterface */ public function getScript() { return ScriptFactory::create()->int($this->version)->push($this->program)->getScript(); }
/** * @param array $signatures * @param array $publicKeys * @return Script|ScriptInterface */ public function makeScriptSig(array $signatures = [], array $publicKeys = []) { $newScript = new Script(); if (count($signatures) > 0) { $newScript = ScriptFactory::scriptSig()->multisig($signatures); } return $newScript; }
$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))); }
/** * @param TransactionSignatureInterface[] $signatures * @param PublicKeyInterface[] $publicKeys * @return Script|ScriptInterface */ public function makeScriptSig(array $signatures = [], array $publicKeys = []) { $newScript = new Script(); if (count($signatures) > 0) { $sequence = [Opcodes::OP_0]; foreach ($signatures as $sig) { $sequence[] = $sig->getBuffer(); } $newScript = ScriptFactory::sequence($sequence); } return $newScript; }
/** * @param Buffer $secret * @param PublicKeyInterface $a1 * @param PublicKeyInterface $a2 * @param PublicKeyInterface $b1 * @param PublicKeyInterface $b2 * @return ScriptInterface */ public function payToLightningChannel(Buffer $secret, PublicKeyInterface $a1, PublicKeyInterface $a2, PublicKeyInterface $b1, PublicKeyInterface $b2) { return ScriptFactory::create()->op('OP_DEPTH')->op('OP_3')->op('OP_EQUAL')->op('OP_IF')->op('OP_HASH160')->push(Hash::sha256ripe160($secret))->op('OP_EQUALVERIFY')->concat(ScriptFactory::scriptPubKey()->multisig(2, [$a1, $b1]))->op('OP_ELSE')->concat(ScriptFactory::scriptPubKey()->multisig(2, [$a2, $b2]))->op('OP_ENDIF')->getScript(); }
<?php require "../vendor/autoload.php"; use BitWasp\Bitcoin\Bitcoin; use BitWasp\Bitcoin\Key\PrivateKeyFactory; use BitWasp\Bitcoin\Script\ScriptFactory; use BitWasp\Bitcoin\Transaction\Factory\TxSigner; use BitWasp\Bitcoin\Transaction\Factory\TxBuilder; $ecAdapter = Bitcoin::getEcAdapter(); // Two users independently create private keys. $pk1 = PrivateKeyFactory::fromHex('421c76d77563afa1914846b010bd164f395bd34c2102e5e99e0cb9cf173c1d87'); $pk2 = PrivateKeyFactory::fromHex('f7225388c1d69d57e6251c9fda50cbbf9e05131e5adb81e5aa0422402f048162'); // They exchange public keys, and a multisignature address is made. $redeemScript = ScriptFactory::scriptPubKey()->multisig(2, [$pk1->getPublicKey(), $pk2->getPublicKey()]); $os = ScriptFactory::scriptPubKey()->payToScriptHash($redeemScript); // The address is funded with a transaction (fake, for the purposes of this script). // You would do getrawtransaction normall $fundTx = (new TxBuilder())->input('4141414141414141414141414141414141414141414141414141414141414141', 0)->output(50, $os)->get(); // One party wants to spend funds. He creates a transaction spending the funding tx to his address. $spendTx = (new TxBuilder())->spendOutputFrom($fundTx, 0)->payToAddress(50, $pk1->getAddress())->get(); // Two parties sign the transaction (can be done in steps) $signer = new TxSigner($ecAdapter, $spendTx); $signer->sign(0, $pk1, $os, $redeemScript)->sign(0, $pk2, $os, $redeemScript); $rawTx = $signer->get()->getHex(); echo "Fully signed transaction: " . $signer->get()->getHex() . "\n";
/** * @param AddressInterface $address * @param $value * @return PaymentRequestBuilder */ public function addAddressPayment(AddressInterface $address, $value) { $script = ScriptFactory::scriptPubKey()->payToAddress($address); $output = new TransactionOutput($value, $script); return $this->addOutput($output); }
<?php require_once "../vendor/autoload.php"; use BitWasp\Bitcoin\Script\ScriptFactory; use BitWasp\Bitcoin\Transaction\Transaction; use BitWasp\Bitcoin\Script\Script; $ec = \BitWasp\Bitcoin\Bitcoin::getEcAdapter(); $scriptSig = ScriptFactory::create()->int(1)->int(1)->getScript(); $scriptPubKey = ScriptFactory::create()->op('OP_ADD')->int(2)->op('OP_EQUAL')->getScript(); echo "Formed script: " . $scriptSig->getHex() . " " . $scriptPubKey->getHex() . "\n"; $flags = new \BitWasp\Bitcoin\Flags(0); $i = new \BitWasp\Bitcoin\Script\Interpreter\Interpreter($ec, new Transaction(), $flags); $result = $i->verify($scriptSig, $scriptPubKey, 0); echo "Script result: " . ($result ? 'true' : 'false') . "\n";
<?php require_once "../vendor/autoload.php"; use BitWasp\Bitcoin\Script\ScriptFactory; $script = ScriptFactory::fromHex($argv[1]); print_r($script->getScriptParser()->getHumanReadable());
/** * P2shScript constructor. * @param ScriptInterface $script * @param Opcodes|null $opcodes */ public function __construct(ScriptInterface $script, Opcodes $opcodes = null) { parent::__construct($script->getBuffer(), $opcodes); $this->outputScript = ScriptFactory::scriptPubKey()->payToScriptHash($script); }
use BitWasp\Bitcoin\Key\PrivateKeyFactory; use BitWasp\Bitcoin\Key\PublicKeyFactory; use BitWasp\Bitcoin\Address\AddressFactory; use BitWasp\Bitcoin\Rpc\RpcFactory; $network = Bitcoin::getNetwork(); $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()); $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);
/** * @param TransactionSignatureInterface $signature * @return Script */ public function payToPubKey(TransactionSignatureInterface $signature) { return ScriptFactory::create()->push($signature->getBuffer()); }
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; }