/** * build inputs and outputs lists for TransactionBuilder * * @param TransactionBuilder $txBuilder * @return array * @throws \Exception */ public function buildTx(TransactionBuilder $txBuilder) { $send = $txBuilder->getOutputs(); $utxos = $txBuilder->getUtxos(); foreach ($utxos as $utxo) { if (!$utxo->address || !$utxo->value || !$utxo->scriptPubKeyHex) { $tx = $this->sdk->transaction($utxo->hash); if (!$tx || !isset($tx['outputs'][$utxo->index])) { throw new \Exception("Invalid output [{$utxo->hash}][{$utxo->index}]"); } $output = $tx['outputs'][$utxo->index]; if (!$utxo->address) { $utxo->address = $output['address']; } if (!$utxo->value) { $utxo->value = $output['value']; } if (!$utxo->scriptPubKeyHex) { $utxo->scriptPubKeyHex = $output['script_hex']; } } if (!$utxo->path) { $address = $utxo->address; if (!BitcoinLib::validate_address($address)) { throw new \Exception("Invalid address [{$address}]"); } $utxo->path = $this->getPathForAddress($address); } if (!$utxo->redeemScript) { list(, $redeemScript) = $this->getRedeemScriptByPath($utxo->path); $utxo->redeemScript = $redeemScript; } } if (array_sum(array_map(function (UTXO $utxo) { return $utxo->value; }, $utxos)) < array_sum(array_column($send, 'value'))) { throw new \Exception("Atempting to spend more than sum of UTXOs"); } list($fee, $change) = $this->determineFeeAndChange($txBuilder); if ($txBuilder->getValidateChange() !== null && $txBuilder->getValidateChange() != $change) { throw new \Exception("the amount of change suggested by the coin selection seems incorrect"); } if ($txBuilder->getValidateFee() !== null && $txBuilder->getValidateFee() != $fee) { throw new \Exception("the fee suggested by the coin selection ({$txBuilder->getValidateFee()}) seems incorrect ({$fee})"); } if ($change > 0) { $send[] = ['address' => $txBuilder->getChangeAddress() ?: $this->getNewAddress(), 'value' => $change]; } // create raw transaction $inputs = array_map(function (UTXO $utxo) { return ['txid' => $utxo->hash, 'vout' => (int) $utxo->index, 'address' => $utxo->address, 'scriptPubKey' => $utxo->scriptPubKeyHex, 'value' => $utxo->value, 'path' => $utxo->path, 'redeemScript' => $utxo->redeemScript]; }, $utxos); // outputs should be randomized to make the change harder to detect if ($txBuilder->shouldRandomizeChangeOuput()) { shuffle($send); } return [$inputs, $send]; }