| ScriptPubKey | : OP_HASH160 <redeemScriptHash> OP_EQUAL |
| ScriptSig | : OP_0 < ... > OP_PUSHDATA1 <redeemScript> |
| Redeem Script | : < ... > OP_CHECKMULTISIG |
| ScriptSig | : |
| ScriptPubKey | : |
<?php
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Network\NetworkFactory;
use BitWasp\Buffertools\Buffer;
use BitWasp\Bitcoin\Key\Factory\PublicKeyFactory;
use BitWasp\Bitcoin\Script\ScriptFactory;
use BitWasp\Bitcoin\Script\P2shScript;
use BitWasp\Bitcoin\Script\Opcodes;
include_once "../libraries/vendor/autoload.php";
$M_N_Range = range(1,15);
include_once("html_iframe_header.php");
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
try {
$networkClass = $_POST['network'];
Bitcoin::setNetwork(NetworkFactory::$networkClass());
$network = Bitcoin::getNetwork();
$pubKeys = [];
$publicKeyFactory = new PublicKeyFactory();
if (!in_array($_POST['reqsig'], $M_N_Range)) {
throw new Exception("'Required Signature' value is not valid.");
} else {
foreach($_POST['pubkey'] as $pubkey_hex) {
if (strlen($pubkey_hex) > 0 AND !ctype_xdigit($pubkey_hex)) {
throw new Exception("Public key must be hex.");
}
if (strlen($pubkey_hex) > 0 AND ctype_xdigit($pubkey_hex)) {
$validPubKeys[] = $publicKeyFactory->fromHex($pubkey_hex);;
}
}
}
if ($_POST['reqsig'] > count($validPubKeys)) {
throw new Exception("Required signature value should not exceed number of public key.");
}
// make a n-of-m multisignature script
$multisig = ScriptFactory::scriptPubKey()->multisig($_POST['reqsig'], $validPubKeys, $sort = false);
// use the P2shScript 'decorator' to 'extend' script with extra functions relevant to a P2SH script
$redeemScript = new P2shScript($multisig);
$scriptPubKey = $redeemScript->getOutputScript();
$opcodes = $scriptPubKey->getOpcodes();
?>
<div class="table-responsive">
<h6 class="mt-3">P2SH.Multisig</h6>
<table border=0 class='table'>
<tr style='background-color:#f0f0f0'><td>Base58 address</td><td><?php echo $redeemScript->getAddress()->getAddress();?></td></tr>
<tr><td>Redeem Script Hex </td><td><?php echo $redeemScript->getHex();?></td></tr>
<tr><td>Redeem Script Asm</td>
<td>
<?php
foreach( $redeemScript->getScriptParser()->decode() as $operation ) {
if ($operation->isPush()) {
echo htmlentities("<{$operation->getData()->getHex()}> ");
} else {
echo $opcodes->getOp($operation->getOp()) . " " ;
}
}
?>
</td>
</tr>
<tr><td>Redeem Script Hash Hex</td><td><?php echo $redeemScript->getScriptHash()->getHex();?></td></tr>
<tr style='background-color:#f0f0f0'><td>ScriptPubKey Hex </td><td><?php echo $scriptPubKey->getHex()?></td></tr>
<tr style='background-color:#f0f0f0'><td>ScriptPubKey Asm</td>
<td>
<?php
foreach( $scriptPubKey->getScriptParser()->decode() as $operation ) {
if ($operation->isPush()) {
echo htmlentities("<{$operation->getData()->getHex()}> ");
} else {
echo $opcodes->getOp($operation->getOp()) . " " ;
}
}
?>
</td>
</tr>
</table>
<?php
if (@count($validPubKeys) <= 3) {
?>
<h6 class="mt-3">P2MS</h6>
<table border=0 class='table'>
<tr><td>ScriptPubKey Hex </td><td><?php echo $redeemScript->getHex();?></td></tr>
<tr><td>ScriptPubKey Asm</td>
<td>
<?php
foreach( $redeemScript->getScriptParser()->decode() as $operation ) {
if ($operation->isPush()) {
echo htmlentities("<{$operation->getData()->getHex()}> ");
} else {
echo $opcodes->getOp($operation->getOp()) . " " ;
}
}
?>
</td>
</tr>
</table>
<?php
}
?>
</div>
<?php
} catch (Exception $e) {
$errmsg .= "Problem found. " . $e->getMessage();
}
}
if ($errmsg) {
?>
<div class="alert alert-danger">
<strong>Error!</strong> <?php echo $errmsg?>
</div>
<?php
}
?>
<form action='' method='post'>
<div class="form-group">
<label for="network">Network:</label>
<select id="network" name="network" class="form-control" >
<?php
$networks = get_class_methods(new NetworkFactory());
foreach($networks as $network) {
echo "<option value='{$network}'".($network == $_POST['network'] ? " selected": "").">{$network}</option>";
}
?>
</select>
</div>
<div class="form-group">
<label for="pubkey">Public Key Hex:</label>
<div class="input-group mb-3">
<input class="form-control" type='text' name='pubkey[]' id='pubkey' value='<?php echo $_POST['pubkey'][0]?>'>
<div class="input-group-append">
<input class="btn btn-success" type="button" value="+" onclick="$('#multisig-pubkey-holder').find('div').first().clone().appendTo('#multisig-pubkey-holder')"/>
</div>
</div>
</div>
<?php
$displayPublickey = count($_POST['pubkey'])-1;
$displayPublickey = max(1, $displayPublickey);
?>
<div id="multisig-pubkey-holder" class="form-group">
<?php
foreach(range(1, $displayPublickey) as $n) {
?>
<div class="input-group mb-3">
<input class="form-control" type='text' name='pubkey[]' value='<?php echo $_POST['pubkey'][$n]?>'>
<div class="input-group-append">
<input class="btn btn-success" type="button" value=" - " onclick="
var length = $(this).closest('#multisig-pubkey-holder').find('input[value=\' - \']').length;
if (length > 1) {
$(this).parent('div').parent('div').remove();
} else {
alert('At least 2 public keys are required');
}
"/>
</div>
</div>
<?Php
}
?>
</div>
<div class="form-group">
<label for="reqsig">Required Signature To Spend:</label>
<select id="reqsig" name="reqsig" class="form-control" >
<?php
foreach($M_N_Range as $k) {
echo "<option value='{$k}'".($k == $_POST['reqsig'] ? " selected": "").">{$k}</option>";
}
?>
</select>
</div>
<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");
<?php
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Buffertools\Buffer;
use BitWasp\Bitcoin\Network\NetworkFactory;
use BitWasp\Bitcoin\Key\Factory\PrivateKeyFactory;
use BitWasp\Bitcoin\Address\AddressCreator;
use BitWasp\Bitcoin\Transaction\Factory\TxBuilder;
use BitWasp\Bitcoin\Transaction\TransactionFactory;
use BitWasp\Bitcoin\Transaction\TransactionOutput;
use BitWasp\Bitcoin\Transaction\Factory\Signer;
use BitWasp\Bitcoin\Script\ScriptType;
use BitWasp\Bitcoin\Script\ScriptFactory;
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
include_once "../libraries/vendor/autoload.php";
$noOfInputs = 10;
$noOfOutputs = 1;
include_once("html_iframe_header.php");
if ($_GET['tab'] == 'form2_tabitem1' AND $_SERVER['REQUEST_METHOD'] == 'POST') {
try {
$networkClass = $_POST['network'];
Bitcoin::setNetwork(NetworkFactory::$networkClass());
$network = Bitcoin::getNetwork();
$ecAdapter = Bitcoin::getEcAdapter();
$privKeyFactory = new PrivateKeyFactory();
$addrCreator = new AddressCreator();
$spendTx = TransactionFactory::build();
$signItems = [];
if (!is_numeric($_POST['no_of_inputs']) OR !is_numeric($_POST['no_of_outputs'])) {
throw new Exception("Error in 'no_of_inputs' or 'no_of_outputs'.");
}
foreach(range(1,$_POST['no_of_inputs']) as $thisInput) {
$utxoHash = trim($_POST["utxo_hash_{$thisInput}"]);
$utxoNOutput = trim($_POST["utxo_n_{$thisInput}"]);
$privkeyhex = trim($_POST["privkey_{$thisInput}"]);
$utxoScript = trim($_POST["utxo_script_{$thisInput}"]);
if (strlen($utxoHash)>0 AND strlen($utxoNOutput) > 0 AND strlen($privkeyhex) > 0) {
$spendTx = $spendTx->input($utxoHash, $utxoNOutput);
$signItems[] = [$privkeyhex, $utxoScript];
} else {
throw new Exception("Error in 'input#{$thisInput}'.");
}
}
foreach(range(1,$_POST['no_of_outputs']) as $thisOutput) {
$address = trim($_POST["address_{$thisOutput}"]);
$amount = trim($_POST["amount_{$thisOutput}"]);
if (!strlen($address) or !strlen($amount)) {
throw new Exception("Error in 'output#{$thisOutput}'.");
}
if (ctype_xdigit($address)) {//hex
$recipient = ScriptFactory::fromHex($address);
$decodeScript = (new OutputClassifier())->decode($recipient);
if ($decodeScript->getType() != ScriptType::MULTISIG) {
throw new Exception("Invalid P2MS output in 'output#{$thisOutput}' (Check scriptPubKey).");
}
$spendTx = $spendTx->output($amount, $recipient);
} else {
$recipient = $addrCreator->fromString($address);
$decodeScript = (new OutputClassifier())->decode($recipient->getScriptPubKey());
if ($decodeScript->getType() != ScriptType::P2SH) {
throw new Exception("Invalid P2SH addresss in 'output#{$thisOutput}' (Check scriptPubKey).");
}
$spendTx = $spendTx->payToAddress($amount, $recipient);
}
}
$thisTx = $spendTx->get();
$signer = new Signer($thisTx, $ecAdapter);
foreach($signItems as $nIn=>$signItem) {
$privateKey = $privKeyFactory->fromHexCompressed($signItem[0]);
$scriptPubKey = ScriptFactory::fromHex($signItem[1]);
$txOutput = new TransactionOutput(0, $scriptPubKey );
$signer = $signer->sign($nIn, $privateKey, $txOutput);
}
?>
<div class="alert alert-success">
<h6 class="mt-3">Final TX Hex</h6>
<textarea class="form-control" rows="5" id="comment" readonly><?php echo $signer->get()->getHex();?></textarea>
</div>
<?php
} catch (Exception $e) {
$errmsg .= "Problem found. " . $e->getMessage();
}
}
if ($errmsg) {
?>
<div class="alert alert-danger">
<strong>Error!</strong> <?php echo $errmsg?>
</div>
<?php
}
?>
<form action='?tab=form2_tabitem1#hashtag2' method='post'>
<div class="form-group">
<label for="network">Network: </label>
<select name="network" id="network" class="form-control">
<?php
$networks = get_class_methods(new NetworkFactory());
foreach($networks as $network) {
echo "<option value='{$network}'".($network == $_POST['network'] ? " selected": "").">{$network}</option>";
}
?>
</select>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-row">
<div class="form-group col">
<label for="no_of_inputs">Inputs: </label>
<select class="form-control" style="width:auto;" id="no_of_inputs" name='no_of_inputs' onchange="
var self = $(this);
var thisvalue = self.val();
var form = self.closest('form');
$('div[id^=row_input_]',form).hide();
for(var i=1; i<= thisvalue; i++) {
$('div[id=row_input_'+ i + ']',form).show();
}
">
<?php
foreach(range(1,$noOfInputs) as $thisInput) {
echo "<option value='{$thisInput}'".($thisInput == $_POST['no_of_inputs'] ? " selected": "").">{$thisInput}</option>";
}
?>
</select>
</div>
</div>
<?php
$selected_n_inputs = is_numeric($_POST['no_of_inputs']) ? $_POST['no_of_inputs'] : 1;
foreach(range(1,$noOfInputs) as $thisInput) {
?>
<div class="form-row" id='row_input_<?php echo $thisInput?>' style="<?php echo ($thisInput > $selected_n_inputs) ? "display:none" : "display:;"?>">
<div class="form-group col-sm-1">
#<?php echo $thisInput?>
</div>
<div class="form-group col-sm-3">
<input class="form-control" title="UTXO Tx Hash" placeholder='UTXO Tx Hash' type='text' name='utxo_hash_<?php echo $thisInput?>' value='<?php echo $_POST["utxo_hash_{$thisInput}"]?>'>
</div>
<div class="form-group col-sm-1">
<input class="form-control" title="UTXO N Output" placeholder='N' type='text' name='utxo_n_<?php echo $thisInput?>' value='<?php echo $_POST["utxo_n_{$thisInput}"]?>'>
</div>
<div class="form-group col-sm-3">
<input class="form-control" title="UTXO ScriptPubKey" placeholder='UTXO ScriptPubKey' type='text' name='utxo_script_<?php echo $thisInput?>' value='<?php echo $_POST["utxo_script_{$thisInput}"]?>'>
</div>
<div class="form-group col-sm-4">
<input class="form-control" title="Private Key Hex, for signing purpose." placeholder='Private Key Hex' type='text' name='privkey_<?php echo $thisInput?>' value='<?php echo $_GET['tab'] == 'form2_tabitem1' ?$_POST["privkey_{$thisInput}"] : ''?>'>
</div>
</div>
<?php
}
?>
</div>
<div class="col-sm-6">
<div class="form-row">
<div class="form-group col">
<label for="no_of_outputs">Outputs:</label> <select class="form-control" id="no_of_outputs" name='no_of_outputs' style='width:auto;' onchange="
var self = $(this);
var thisvalue = self.val();
var form = self.closest('form');
$('div[id^=row_output_]',form).hide();
for(var i=1; i<= thisvalue; i++) {
$('div[id=row_output_'+ i + ']',form).show();
}
">
<?php
foreach(range(1,$noOfOutputs) as $thisOutput) {
echo "<option value='{$thisOutput}'".($thisOutput == $_POST['no_of_outputs'] ? " selected": "").">{$thisOutput}</option>";
}
?>
</select>
</div>
</div>
<?php
$selected_n_outputs = is_numeric($_POST['no_of_outputs']) ? $_POST['no_of_outputs'] : 1;
foreach(range(1,$noOfOutputs) as $thisOutput) {
?>
<div class="form-row" id='row_output_<?php echo $thisOutput?>' style="<?php echo ($thisOutput > $selected_n_outputs) ? "display:none" : "display:;"?>">
<div class="form-group col-sm-1">
#<?php echo $thisOutput?>
</div>
<div class="form-group col-sm-6">
<input class="form-control" title='P2SH.Multisig Address / P2MS ScriptPubKey' placeholder='P2SH.Multisig Address / P2MS ScriptPubKey' type='text' name='address_<?php echo $thisOutput?>' value='<?php echo $_POST["address_{$thisOutput}"]?>'>
</div>
<div class="form-group col-sm-5">
<input class="form-control" placeholder='Amount' type='text' name='amount_<?php echo $thisOutput?>' value='<?php echo $_POST["amount_{$thisOutput}"]?>'>
</div>
</div>
<?php
}
?>
</div>
</div>
<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");
<?php
use BitWasp\Bitcoin\Bitcoin;
use BitWasp\Bitcoin\Network\NetworkFactory;
use BitWasp\Buffertools\Buffer;
use BitWasp\Bitcoin\Key\Factory\PublicKeyFactory;
use BitWasp\Bitcoin\Script\ScriptFactory;
use BitWasp\Bitcoin\Script\P2shScript;
use BitWasp\Bitcoin\Script\Opcodes;
include_once "../libraries/vendor/autoload.php";
$M_N_Range = range(1,15);
include_once("html_iframe_header.php");
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
try {
$networkClass = $_POST['network'];
Bitcoin::setNetwork(NetworkFactory::$networkClass());
$network = Bitcoin::getNetwork();
$pubKeys = [];
$publicKeyFactory = new PublicKeyFactory();
if (!in_array($_POST['reqsig'], $M_N_Range)) {
throw new Exception("'Required Signature' value is not valid.");
} else {
foreach($_POST['pubkey'] as $pubkey_hex) {
if (strlen($pubkey_hex) > 0 AND !ctype_xdigit($pubkey_hex)) {
throw new Exception("Public key must be hex.");
}
if (strlen($pubkey_hex) > 0 AND ctype_xdigit($pubkey_hex)) {
$validPubKeys[] = $publicKeyFactory->fromHex($pubkey_hex);;
}
}
}
if ($_POST['reqsig'] > count($validPubKeys)) {
throw new Exception("Required signature value should not exceed number of public key.");
}
// make a n-of-m multisignature script
$multisig = ScriptFactory::scriptPubKey()->multisig($_POST['reqsig'], $validPubKeys, $sort = false);
// use the P2shScript 'decorator' to 'extend' script with extra functions relevant to a P2SH script
$redeemScript = new P2shScript($multisig);
$scriptPubKey = $redeemScript->getOutputScript();
$opcodes = $scriptPubKey->getOpcodes();
?>
<div class="table-responsive">
<h6 class="mt-3">P2SH.Multisig</h6>
<table border=0 class='table'>
<tr style='background-color:#f0f0f0'><td>Base58 address</td><td><?php echo $redeemScript->getAddress()->getAddress();?></td></tr>
<tr><td>Redeem Script Hex </td><td><?php echo $redeemScript->getHex();?></td></tr>
<tr><td>Redeem Script Asm</td>
<td>
<?php
foreach( $redeemScript->getScriptParser()->decode() as $operation ) {
if ($operation->isPush()) {
echo htmlentities("<{$operation->getData()->getHex()}> ");
} else {
echo $opcodes->getOp($operation->getOp()) . " " ;
}
}
?>
</td>
</tr>
<tr><td>Redeem Script Hash Hex</td><td><?php echo $redeemScript->getScriptHash()->getHex();?></td></tr>
<tr style='background-color:#f0f0f0'><td>ScriptPubKey Hex </td><td><?php echo $scriptPubKey->getHex()?></td></tr>
<tr style='background-color:#f0f0f0'><td>ScriptPubKey Asm</td>
<td>
<?php
foreach( $scriptPubKey->getScriptParser()->decode() as $operation ) {
if ($operation->isPush()) {
echo htmlentities("<{$operation->getData()->getHex()}> ");
} else {
echo $opcodes->getOp($operation->getOp()) . " " ;
}
}
?>
</td>
</tr>
</table>
<?php
if (@count($validPubKeys) <= 3) {
?>
<h6 class="mt-3">P2MS</h6>
<table border=0 class='table'>
<tr><td>ScriptPubKey Hex </td><td><?php echo $redeemScript->getHex();?></td></tr>
<tr><td>ScriptPubKey Asm</td>
<td>
<?php
foreach( $redeemScript->getScriptParser()->decode() as $operation ) {
if ($operation->isPush()) {
echo htmlentities("<{$operation->getData()->getHex()}> ");
} else {
echo $opcodes->getOp($operation->getOp()) . " " ;
}
}
?>
</td>
</tr>
</table>
<?php
}
?>
</div>
<?php
} catch (Exception $e) {
$errmsg .= "Problem found. " . $e->getMessage();
}
}
if ($errmsg) {
?>
<div class="alert alert-danger">
<strong>Error!</strong> <?php echo $errmsg?>
</div>
<?php
}
?>
<form action='' method='post'>
<div class="form-group">
<label for="network">Network:</label>
<select id="network" name="network" class="form-control" >
<?php
$networks = get_class_methods(new NetworkFactory());
foreach($networks as $network) {
echo "<option value='{$network}'".($network == $_POST['network'] ? " selected": "").">{$network}</option>";
}
?>
</select>
</div>
<div class="form-group">
<label for="pubkey">Public Key Hex:</label>
<div class="input-group mb-3">
<input class="form-control" type='text' name='pubkey[]' id='pubkey' value='<?php echo $_POST['pubkey'][0]?>'>
<div class="input-group-append">
<input class="btn btn-success" type="button" value="+" onclick="$('#multisig-pubkey-holder').find('div').first().clone().appendTo('#multisig-pubkey-holder')"/>
</div>
</div>
</div>
<?php
$displayPublickey = count($_POST['pubkey'])-1;
$displayPublickey = max(1, $displayPublickey);
?>
<div id="multisig-pubkey-holder" class="form-group">
<?php
foreach(range(1, $displayPublickey) as $n) {
?>
<div class="input-group mb-3">
<input class="form-control" type='text' name='pubkey[]' value='<?php echo $_POST['pubkey'][$n]?>'>
<div class="input-group-append">
<input class="btn btn-success" type="button" value=" - " onclick="
var length = $(this).closest('#multisig-pubkey-holder').find('input[value=\' - \']').length;
if (length > 1) {
$(this).parent('div').parent('div').remove();
} else {
alert('At least 2 public keys are required');
}
"/>
</div>
</div>
<?Php
}
?>
</div>
<div class="form-group">
<label for="reqsig">Required Signature To Spend:</label>
<select id="reqsig" name="reqsig" class="form-control" >
<?php
foreach($M_N_Range as $k) {
echo "<option value='{$k}'".($k == $_POST['reqsig'] ? " selected": "").">{$k}</option>";
}
?>
</select>
</div>
<input type='submit' class="btn btn-success btn-block"/>
</form>
<?php
include_once("html_iframe_footer.php");