13 Commits

Author SHA1 Message Date
root b4fd55aebe added feature to rebuild a transaction from the txid, useful for RBF and double spending :o. Changed donation address. Released as version 1.6 2020-07-06 21:33:57 +00:00
root f51be92a72 fixed multisig bug as described in issues/212 2020-07-05 20:21:41 +00:00
root 06cf50abb3 removed auto reload wallet feature. users must click or interact with the page. attempt to save on bandwidth. 2020-06-03 17:59:47 +00:00
root 35de4228d8 updated index.html to list link to new host 2020-04-22 20:18:08 +00:00
OutCast3k a4ef169031 update sha1sum 2020-02-23 19:57:33 +00:00
OutCast3k 6bb5e3785a Merge pull request #210 from junderw/patch-1
Don't add padding to P2WSH
2020-02-23 19:55:14 +00:00
OutCast3k a199d3a55c Merge pull request #208 from jmacxx/fix_bech32_address_decoding
fix: some bech32 addresses were not recognised
2020-02-23 19:54:46 +00:00
Jonathan Underwood 7e92530e1a Don't add padding to P2WSH
Fixes #209
2020-02-20 10:12:57 +09:00
Wowee0 f5c2f48efc fix: some bech32 addresses were not recognised 2020-02-12 10:57:15 -06:00
OutCast3k 4f3ceeb3ea update date in sha1sum file 2019-12-28 12:10:39 +00:00
OutCast3k 73369dd253 add file hash of test.html to sha1sum 2019-12-28 12:08:51 +00:00
OutCast3k 6ed0d3e07e Merge pull request #206 from jmacxx/tests
add some self-test routines to coinbin
2019-12-28 12:03:55 +00:00
Wowee0 84304f23ea tests added 2019-12-25 19:30:38 -06:00
6 changed files with 492 additions and 50 deletions
+9 -8
View File
@@ -1,7 +1,7 @@
coinbin
=======
A Open Source Browser Based Bitcoin Wallet. Version 1.5 beta by OutCast3k
A Open Source Browser Based Bitcoin Wallet. Version 1.6 beta by OutCast3k
Live version available at http://coinb.in/ or http://4zpinp6gdkjfplhk.onion
@@ -24,12 +24,13 @@ Coinb.in supports a number of key features such as:
- Brain wallet support.
- Compatible with bitcoin-qt
- An offical .onion address for tor users.
- Offline qrcode creator and scanning tool
- HD (bip32) support
- Supports altcoins such as litecoin
- Replace by fee (RBF) Support
- Segwit Support
- Bech32 address support
- Offline qrcode creator and scanning tool.
- HD (bip32) support.
- Supports altcoins such as litecoin.
- Replace by fee (RBF) Support.
- Segwit Support.
- Bech32 address support.
- Fee calculator - https://coinb.in/#fees
- Transaction rebuild support for RBF and double spending.
Donate to 3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN to see more development!
Donate to 33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G to see more development!
+5 -4
View File
@@ -643,7 +643,7 @@
<label>Replace By Fee (RBF)</label>
<p class="checkbox">
<label><input type="checkbox" id="txRBF" class="checkbox-inline"> Make this a <a href="https://en.bitcoin.it/wiki/Transaction_replacement" target="_blank">RBF transaction</a>.</label>
<label><input type="checkbox" id="txRBF" class="checkbox-inline" checked> Make this a <a href="https://en.bitcoin.it/wiki/Transaction_replacement" target="_blank">RBF transaction</a>.</label>
</p>
<hr>
@@ -1333,7 +1333,7 @@
<div class="tab-pane tab-content" id="about">
<h2>About <small>open source bitcoin wallet</small></h2>
<p>Version 1.5</p>
<p>Version 1.6</p>
<p>Compatible with bitcoin core</p>
<p>Github <a href="https://github.com/OutCast3k/coinbin/">https://github.com/OutCast3k/coinbin/</a></p>
<p>TOR <a href="http://4zpinp6gdkjfplhk.onion">4zpinp6gdkjfplhk.onion</a></p>
@@ -1343,12 +1343,13 @@
<h3>Information</h3>
<p>Coinb.in is a free and open source project released under the MIT license, originally by <a href="https://bitcointalk.org/index.php?action=profile;u=34834" target="_blank">OutCast3k</a> in 2013. Discussion of the project can be found at <a href="https://bitcointalk.org/index.php?topic=390046" target="_blank">bitcointalk.org</a> during its early testing stages when its primary focus was to develop a proof of concept multisig solution in javascript.</p>
<p>Coinb.in is run and funded by the generosity of others in terms of <a href="https://github.com/OutCast3k/coinbin/graphs/contributors" target="_blank">development</a> and hosting.</p>
<p>Coinb.in is kindly hosted by <a href="https://www.bitvps.com/" target="_blank">BitVPS.com</a>.</p>
<h3>Privacy</h3>
<p>Coinb.in believes strongly in privacy, not only do we support the use of TOR, the site does not collect and store IP or transaction data via our servers nor do we store your bitcoins private key. We do route traffic via cloudflare using an SSL certificate.</p>
<h3>Support</h3>
<p>We recommend that you first check our <a href="https://status.coinb.in/" target="_blank">service status</a> page and then <a href="https://blog.coinb.in/" target="_blank">blog</a> page which has multiple <a href="https://blog.coinb.in/guides" target="_blank">guides</a>. However if the problem persists you can contact us by emailing support{at}coinb.in.</p>
<h3>Donate</h3>
<p>Please donate to <a href="bitcoin:3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN">3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN</a> if you found this project useful or want to see more features!</p>
<p>Please donate to <a href="bitcoin:33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G">33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G</a> if you found this project useful or want to see more features!</p>
</div>
<div class="tab-pane tab-content" id="settings">
@@ -1474,7 +1475,7 @@
<div id="footer">
<div class="container text-right">
<p class="text-muted">Version 1.5</p>
<p class="text-muted">Version 1.6</p>
</div>
</div>
+16 -4
View File
@@ -19,7 +19,7 @@
coinjs.compressed = false;
/* other vars */
coinjs.developer = '3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN'; //bitcoin
coinjs.developer = '33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G'; //bitcoin
/* bit(coinb.in) api vars */
coinjs.hostname = ((document.location.hostname.split(".")[(document.location.hostname.split(".")).length-1]) == 'onion') ? '4zpinp6gdkjfplhk.onion' : 'coinb.in';
@@ -203,7 +203,7 @@
var decode = coinjs.bech32_decode(address);
if(decode){
decode.data.shift();
return Crypto.util.bytesToHex(coinjs.bech32_convert(decode.data, 5, 8, true));
return Crypto.util.bytesToHex(coinjs.bech32_convert(decode.data, 5, 8, false));
}
return r;
}
@@ -307,7 +307,7 @@
return o;
} else {
return false;
throw "Invalid checksum";
}
} catch(e) {
bech32rs = coinjs.bech32redeemscript(addr);
@@ -1067,6 +1067,11 @@
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=unspent&address='+address+'&r='+Math.random(), callback, "GET");
}
/* list transaction data */
r.getTransaction = function(txid, callback) {
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=bitcoin&request=gettransaction&txid='+txid+'&r='+Math.random(), callback, "GET");
}
/* add unspent to transaction */
r.addUnspent = function(address, callback, script, segwit, sequence){
var self = this;
@@ -1336,7 +1341,14 @@
return {'type':'segwit', 'signed':signed, 'signatures': sigs, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[0]), 'value': value};
} else if (this.ins[index].script.chunks[0]==0 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1][this.ins[index].script.chunks[this.ins[index].script.chunks.length-1].length-1]==174) { // OP_CHECKMULTISIG
// multisig script, with signature(s) included
return {'type':'multisig', 'signed':'true', 'signatures':this.ins[index].script.chunks.length-2, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])};
sigcount = 0;
for(i=1; i<this.ins[index].script.chunks.length-1;i++){
if(this.ins[index].script.chunks[i]!=0){
sigcount++;
}
}
return {'type':'multisig', 'signed':'true', 'signatures':sigcount, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])};
} else if (this.ins[index].script.chunks[0]>=80 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]==174) { // OP_CHECKMULTISIG
// multisig script, without signature!
return {'type':'multisig', 'signed':'false', 'signatures':0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
+77 -29
View File
@@ -65,7 +65,6 @@ $(document).ready(function() {
$("#openWallet").removeClass("hidden").show();
walletBalance();
checkBalanceLoop();
} else {
$("#openLoginStatus").html("Your passwords do not match!").removeClass("hidden").fadeOut().fadeIn();
}
@@ -133,7 +132,7 @@ $(document).ready(function() {
$("#walletSpend").removeClass("hidden").addClass("hidden");
});
$("#walletBalance").click(function(){
$("#walletBalance, #walletAddress, #walletQrCode").click(function(){
walletBalance();
});
@@ -297,28 +296,20 @@ $(document).ready(function() {
});
function walletBalance(){
var tx = coinjs.transaction();
$("#walletLoader").removeClass("hidden");
coinjs.addressBalance($("#walletAddress").html(),function(data){
if($(data).find("result").text()==1){
var v = $(data).find("balance").text()/100000000;
$("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn();
} else {
if($("#walletLoader").hasClass("hidden")){
var tx = coinjs.transaction();
$("#walletLoader").removeClass("hidden");
coinjs.addressBalance($("#walletAddress").html(),function(data){
if($(data).find("result").text()==1){
var v = $(data).find("balance").text()/100000000;
$("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn();
} else {
$("#walletBalance").html("0.00 BTC").attr('rel',v).fadeOut().fadeIn();
}
}
$("#walletLoader").addClass("hidden");
});
}
function checkBalanceLoop(){
clearTimeout(wallet_timer);
wallet_timer = setTimeout(function(){
if($("#walletLoader").hasClass("hidden")){
walletBalance();
}
checkBalanceLoop();
},45000);
$("#walletLoader").addClass("hidden");
});
}
}
/* new -> address code */
@@ -890,7 +881,7 @@ $(document).ready(function() {
$("#redeemFromStatus, #redeemFromAddress").addClass('hidden');
if(redeem.from=='multisigAddress'){
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> You should use the redeem script, not the multisig address!');
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> You should use the redeem script, not its address!');
return false;
}
@@ -982,9 +973,15 @@ $(document).ready(function() {
r.redeemscript = true;
r.decodescript = decodeRs;
} else { // something else
r.addr = '';
r.from = 'other';
r.redeemscript = false;
if(string.match(/^[a-f0-9]{64}$/i)){
r.addr = string;
r.from = 'txid';
r.redeemscript = false;
} else {
r.addr = '';
r.from = 'other';
r.redeemscript = false;
}
}
}
return r;
@@ -1051,9 +1048,61 @@ $(document).ready(function() {
}
}
/* global function to add inputs to page */
function addInput(address, amount) {
if($("#recipients .recipient:last .address:last").val() != ""){
$("#recipients .addressAddTo:first").click();
};
$("#recipients .address:last").val(address);
$("#recipients .amount:last").val(amount);
}
/* default function to retreive unspent outputs*/
function listUnspentDefault(redeem){
var tx = coinjs.transaction();
// unspent from transaction; double spend and RBF.
if(redeem.from == 'txid'){
tx.getTransaction(redeem.addr, function(data){
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Attempted to rebuild transaction id <a href="'+explorer_tx+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
$.each($(data).find("inputs").children(), function(i,o){
var tx = $(o).find("txid").text();
var n = $(o).find("output_no").text();
var amount = (($(o).find("value").text()*1)).toFixed(8);
var script = coinjs.script();
var s = script.spendToScript($(o).find("address").text());
var scr = Crypto.util.bytesToHex(s.buffer);
addOutput(tx, n, scr, amount);
});
$("#recipients .addressRemoveTo").click();
$("#recipients .address").val("");
$("#recipients .amount").val("");
$.each($(data).find("outputs").children(), function(i,o){
addInput($(o).find("address").text(), $(o).find("value").text());
});
$("#redeemFromBtn").html("Load").attr('disabled',false);
totalInputAmount();
validateOutputAmount();
});
return;
}
// unspent from address
tx.listUnspent(redeem.addr, function(data){
if(redeem.addr) {
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
@@ -1087,10 +1136,9 @@ $(document).ready(function() {
},
success: function(data) {
if (data.address) { // address field will always be present, txrefs is only present if there are UTXOs
$("#redeemFromAddress").removeClass('hidden').html(
'<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
for(var i in data.txrefs){
var o = data.txrefs[i]
var o = data.txrefs[i];
var tx = ((""+o.tx_hash).match(/.{1,2}/g).reverse()).join("")+'';
if(tx.match(/^[a-f0-9]+$/)){
var n = o.tx_output_n;
+6 -5
View File
@@ -1,9 +1,9 @@
---- Version 1.4 2019.12.25 ----
---- Version 1.6 2020.07.06 ----
77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js
3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js
253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js
17cc6a56ee601fbe3858563f26232f64ce12abcb ./js/coinbin.js
dc83017470f3ced2b0d522781b3ccded0d3a8d28 ./js/coin.js
7dd75e07389808d57261bca630a5bab55ce9faef ./js/coinbin.js
228cdcf29d33a5eadd360e85a6220e4853ee4590 ./js/coin.js
988565bc2cb402d63ed5c5fd7ff47c4278efc2c5 ./js/collapse.js
9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js
f7c09f2f5a721371e7d478050119f7e2d58e3ef9 ./js/crypto-sha256-hmac.js
@@ -30,5 +30,6 @@ ca35b697d99cae4d1b60f2d60fcd37771987eb07 ./fonts/glyphicons-halflings-regular.w
de51a8494180a6db074af2dee2383f0a363c5b08 ./fonts/glyphicons-halflings-regular.svg
278e49a86e634da6f2a02f3b47dd9d2a8f26210f ./fonts/glyphicons-halflings-regular.woff
44bc1850f570972267b169ae18f1cb06b611ffa2 ./fonts/glyphicons-halflings-regular.ttf
4665ee4d8ca96db25954f6f3587ac367386eb9e8 ./README.md
9cf7084c331b7c536f5f6e34533300c3d9d3e038 ./index.html
ee481606d8d48f402d152fa632ba9e5f9da7f169 ./README.md
5054e03cff2cfcd1ce5296fe2659ca2d46d64fe4 ./index.html
7130b64e3ef4cf6f2f1550e902f081c58dc053de ./test.html
+379
View File
@@ -0,0 +1,379 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<!-- =================================================================== -->
<head>
<title>TESTING COINBIN</title>
<link rel="stylesheet" href="css/bootstrap.min.css" media="screen">
<link rel="stylesheet" href="css/bootstrap-datetimepicker.min.css">
<link rel="stylesheet" href="css/style.css" media="screen">
<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="js/moment.min.js"></script>
<script type="text/javascript" src="js/transition.js"></script>
<script type="text/javascript" src="js/collapse.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script type="text/javascript" src="js/bootstrap-datetimepicker.min.js"></script>
<script type="text/javascript" src="js/crypto-min.js"></script>
<script type="text/javascript" src="js/crypto-sha256.js"></script>
<script type="text/javascript" src="js/crypto-sha256-hmac.js"></script>
<script type="text/javascript" src="js/sha512.js"></script>
<script type="text/javascript" src="js/ripemd160.js"></script>
<script type="text/javascript" src="js/aes.js"></script>
<script type="text/javascript" src="js/jsbn.js"></script>
<script type="text/javascript" src="js/ellipticcurve.js"></script>
<script type="text/javascript" src="js/coin.js"></script>
</head>
<!-- =================================================================== -->
<body>
<!-- =================================================================== -->
<div id="fwrap">
<!-- Fixed navbar -->
<div id="header" class="navbar navbar-default " role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="#home" class="navbar-brand" id="homeBtn"><img src="images/coinbin.gif" style="height:25px;margin-top:-5px"></a>
</div>
</div>
</div>
<div id="content" class="container">
<div class="tab-content">
<div class="tab-pane tab-content active" id="home">
<br />
<button id="test1Btn" class="btn btn-primary" type="submit">Run Coinbin Test Suite</button>
<br />
<textarea rows=20 cols=86 id="testResults"></textarea>
</div>
</div> <!-- content -->
</div> <!-- wrap -->
</div> <!-- navbar -->
</div> <!-- container -->
</body>
<script type="text/javascript">
$(document).ready(function() {
}); // end of document.ready
$("#test1Btn").click(function(){
{
var testName = "hex private key to compressed address";
var testInput = "0000000000000000000000000000000000000000000000000000000000000001";
var testExpected = "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH";
coinjs.compressed = true;
var pubkeyHex = coinjs.newPubkey(testInput);
var testOutput = coinjs.pubkey2address(pubkeyHex, coinjs.pub);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "hex private key to uncompressed address";
var testInput = "0000000000000000000000000000000000000000000000000000000000000001";
var testExpected = "1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm";
coinjs.compressed = false;
var pubkeyHex = coinjs.newPubkey(testInput);
var testOutput = coinjs.pubkey2address(pubkeyHex, coinjs.pub);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "WIF uncompressed private key to address";
var testInput = "5J1LYLWqNxJBTwdGAmzYnpkqqSuFu48fsHv8jgojFMV2Z8exk9L";
var testExpected ="16SK7HnxBMRxSpLhhdf8RYcqv8MPJiSF6Q";
coinjs.compressed = false;
var testOutput = coinjs.wif2address(testInput).address;
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "raw private key to uncompressed base58check WIF private key";
var testInput = "62A87AD3272B41E67108FEA10C57BA6ED609F2F7A2264A83B690CD45707090D1";
var testExpected = "5JZjfs5wJv1gNkJXCmYpyj6VxciqPkwmK4yHW8zMmPN1PW7Hk7F";
coinjs.compressed = false;
var testOutput = coinjs.privkey2wif(testInput);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "raw private key to compressed base58check WIF private key";
var testInput = "62A87AD3272B41E67108FEA10C57BA6ED609F2F7A2264A83B690CD45707090D1";
var testExpected = "KzXVLY4ni4yznz8LJwdUmNoGpUfebSxiakXRqcGAeuhihzaVe3Rz";
coinjs.compressed = true;
var testOutput = coinjs.privkey2wif(testInput);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "hex ripemd160 hash of public key, to base58check address";
var testInput = "62E907B15CBF27D5425399EBF6F0FB50EBB88F18";
var testExpected = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa";
var testOutput = coinjs.scripthash2address(testInput);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "base58check address, to hex ripemd160 hash of public key";
var testInput = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa";
var testExpected = "62e907b15cbf27d5425399ebf6f0fb50ebb88f18";
var bytes = coinjs.base58decode(testInput);
var front = bytes.slice(1, bytes.length-4);
var testOutput = Crypto.util.bytesToHex(front);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "convert 'Hash 160' to address";
var testInput = "119b098e2e980a229e139a9ed01a469e518e6f26";
var testExpected = "12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX";
var testOutput = coinjs.scripthash2address(testInput);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "convert 'SHA256' to address";
var testInput = "904b8a01c68095a9e825d28082c04b75b1f56277648256985717620e8913b79b";
var testExpected = "1JNC98D5LZbrGHFR8shDwiqLPGfpg15BUM";
var r = ripemd160(Crypto.util.hexToBytes(testInput));
r.unshift(coinjs.pub);
var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
var checksum = hash.slice(0, 4);
var testOutput = coinjs.base58encode(r.concat(checksum));
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "convert WIF private key to address bech32";
var testInput = "L3GzRAGwCqfSNFr6g1NQm7edn29DgAKZJ6owUBqYELpP6Kbim5kM";
var testExpected = "bc1qhmc0vk4xzr37ayv7tlyhns7x4dk04tyvflk8ey";
var pubkey = coinjs.wif2pubkey(testInput);
var testOutput = coinjs.bech32Address(pubkey.pubkey).address;
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "bech32 address, to hex ripemd160 hash of public key";
var testInput = "bc1qhmc0vk4xzr37ayv7tlyhns7x4dk04tyvflk8ey";
var testExpected = "bef0f65aa610e3ee919e5fc979c3c6ab6cfaac8c";
var testOutput = coinjs.bech32redeemscript(testInput);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "prefix1 - WIF compressed private key to address (bitcoin)";
var testInput = "Kx4VFK8gXu4qBv73x9b1KFnWYqKekkprYyfX9QhFUMQhrTUooXKc";
var testExpected = "1NFeCVtA3zuCUAmYheRvfyABnSZCHfrR3j";
var testOutput = coinjs.wif2address(testInput).address;
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "prefix2 - WIF compressed private key to address (bitcoin-testnet)";
var testInput = "92Wn1EBgiwDNT8SC7WMZfcSk2y3mQkLUPAQtwMNYZQGAzCFUTdu";
var testExpected = "mxToLbBqPcSNnqPCSnrYjFv172TFPLjVNf";
var saved = pushNetworkVars("btc-testnet");
var testOutput = coinjs.wif2address(testInput).address;
popNetworkVars(saved);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "prefix3 - WIF compressed private key to address (litecoin)";
var testInput = "6vVAeKejJRV5wgrAqtqi7eQsS4Zf79nkw8xuYntU3JwHCiexYaJ";
var testExpected = "LMzBLYQG2opHvMBihMQgJBboxunoj5pssC";
var saved = pushNetworkVars("ltc-mainnet");
var testOutput = coinjs.wif2address(testInput).address;
popNetworkVars(saved);
addTestOutput(testName, testOutput, testExpected);
}
{
var testName = "prefix4 - WIF compressed private key to address (dogecoin)";
var testInput = "6KayMYAEQfFACQhZUzbBpFhvGzDWSmRtaY9NrPQGig9qVzRCzQf";
var testExpected = "DHEPGdnS46dHT79tkfm5DyhGAbQj4Xi8Ni";
var saved = pushNetworkVars("doge-mainnet");
var testOutput = coinjs.wif2address(testInput).address;
popNetworkVars(saved);
addTestOutput(testName, testOutput, testExpected);
}
{
// this test comes from https://bitcoindev.network/guides/bitcoinjs-lib/bitcoin-script-puzzles/
var testName = "P2SH redeem script to address (bitcoin testnet)";
var testInput = "935587";
var testExpected = "2N7WfHK1ftrTdhWej8rnFNR7guhvhfGWwFR";
var saved = pushNetworkVars("btc-testnet");
var hash = Crypto.SHA256(Crypto.util.hexToBytes(testInput), {asBytes: true});
var r = ripemd160(hash);
r.unshift(coinjs.multisig);
var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
var checksum = hash.slice(0, 4);
var testOutput = coinjs.base58encode(r.concat(checksum));
addTestOutput(testName, testOutput, testExpected);
popNetworkVars(saved);
}
{
// this test comes from https://bitcoindev.network/guides/bitcoinjs-lib/bitcoin-script-puzzles/
var testName = "P2WSH redeem script to address (bitcoin testnet)";
var testInput = "935587";
var testExpected = "bcrt1qpt7c23c0wep9e8up4ywn070w3tqz3828ngy34aj8slsfxrh08ddq2d2pyu";
var hash = Crypto.SHA256(Crypto.util.hexToBytes(testInput), {asBytes: true});
var testOutput = coinjs.bech32_encode(/*coinjs.bech32.hrp*/"bcrt", [coinjs.bech32.version].concat(coinjs.bech32_convert(hash, 8, 5, true)));
addTestOutput(testName, testOutput, testExpected);
}
{
// data from https://bitcoin.stackexchange.com/questions/3374/how-to-redeem-a-basic-tx (runeks)
var testName = "basic transaction building bitcoin";
var testExpectedUnsigned = "0100000001eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2010000001976a914010966776006953d5567439e5e39f86a0d273bee88acffffffff01605af405000000001976a914097072524438d003d23a2f23edb65aae1bb3e46988ac00000000";
var testExpectedSigned = "0100000001eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2010000008a4730440220299fffaf20745458111e7826e5c2cca3b78dd27c97e0a513aab807f0d724103402203247498cfb019bbbd3d629814c8703e974f177478f6fde53503a9b1088852fad01410450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6ffffffff01605af405000000001976a914097072524438d003d23a2f23edb65aae1bb3e46988ac00000000";
var privKeyHex = "18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725";
var inputTx = "f2b3eb2deb76566e7324307cd47c35eeb88413f971d88519859b1834307ecfec";
var inputScript = "76a914010966776006953d5567439e5e39f86a0d273bee88ac";
var inputN = 1;
var address0 = "097072524438d003d23a2f23edb65aae1bb3e469";
var amount = 0.999;
coinjs.compressed = false;
var r = coinjs.transaction();
var wif = coinjs.privkey2wif(privKeyHex);
var address1 = coinjs.scripthash2address(address0);
r.addinput(inputTx, inputN, inputScript, 0xffffffff/*sequence*/);
r.addoutput(address1, amount);
var testOutputUnsigned = r.serialize();
debugger;
r.sign(wif, 1/*sighashtype*/);
var testOutputSigned = r.serialize();
addTestOutput(testName+" (unsigned)", testOutputUnsigned, testExpectedUnsigned);
addTestOutput(testName+" (signed)", testOutputSigned, testExpectedSigned);
}
{
// bitcoin testnet transaction https://tbtc.bitaps.com/04bbae5806d2b8fb17ed9339f42c6f6d731191a974b975d2e1df8e7601e90f6f
var saved = pushNetworkVars("btc-testnet");
var testName = "basic transaction building bitcoin-testnet";
var testExpectedUnsigned = "0100000001c72eabf9f208cacc908538e2609bbe665ffda680e2a6c39475941389dd5b14de000000001976a914b9e16a03bbf40ebb78cbc35e22d72a695f27624088acffffffff01703a0f00000000001976a914a447681601eef322926c0b3de5dfbb4157bbe40988ac00000000";
var testExpectedSigned = "0100000001c72eabf9f208cacc908538e2609bbe665ffda680e2a6c39475941389dd5b14de000000008b483045022100d909d4d3d2b540891c102d06fc8eaf1e9b914b93ea28626990666554a75b369102205a73b38071eab5b0acb8381c1454e7d998c80cd6d229645231b6bc1fb024d1d70141046fad107ba21fae3f047096152d0298291168bc0cb6b834f7cc77510dcb41839206b936649623988f7ca58c6104a22105c5b398912ded514685ebd0d8ac4011c2ffffffff01703a0f00000000001976a914a447681601eef322926c0b3de5dfbb4157bbe40988ac00000000";
var wif = "92Wn1EBgiwDNT8SC7WMZfcSk2y3mQkLUPAQtwMNYZQGAzCFUTdu";
var inputTx = "de145bdd8913947594c3a6e280a6fd5f66be9b60e2388590ccca08f2f9ab2ec7";
var inputScript = "76a914b9e16a03bbf40ebb78cbc35e22d72a695f27624088ac";
var inputN = 0;
var address1 = "mvVaevwNK2SdNj9kcugh29HbSLPhv7xszY";
var amount = 0.00998;
coinjs.compressed = true;
var r = coinjs.transaction();
r.addinput(inputTx, inputN, inputScript, 0xffffffff/*sequence*/);
r.addoutput(address1, amount);
var warnings = new Array;
var testOutputUnsigned = r.serialize();
r.sign(wif, 1/*sighashtype*/, warnings);
var testOutputSigned = r.serialize();
popNetworkVars(saved);
addTestOutput(testName+" (unsigned)", testOutputUnsigned, testExpectedUnsigned);
addTestOutput(testName+" (signed)", testOutputSigned, testExpectedSigned);
}
// create a lot of timelock scripts, compare them to known ones created using bitcoinjs-lib
// focus on edge cases like described in https://github.com/OutCast3k/coinbin/issues/201
// ranges 80-ff, 8000-ffff, 800000-ffffff, 80000000-ffffffff.
{
var testExpected = "HODL_depositAddress: 2NAx7Sx9B6epdUGyPeUEAU2tJiPectEym4F HODL_redeemScript: 050000008000b175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\n" +
"HODL_depositAddress: 2N5VZkAjtGerFUrc3bKjuK3whVEyaoKQceg HODL_redeemScript: 0400000008b175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\n" +
"HODL_depositAddress: 2MyN366sJLwXTMVMsMTHxi1bSJBwZwmNsQ4 HODL_redeemScript: 0400008000b175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\n" +
"HODL_depositAddress: 2NFjqkVBLKXjFLGPDpSoBTbhVsccUrqhRLW HODL_redeemScript: 03000008b175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\n" +
"HODL_depositAddress: 2N555b2vUzCJ5t8DryLYTw6vggH87SrK14b HODL_redeemScript: 03008000b175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\n" +
"HODL_depositAddress: 2N31s67tdRuaVfQipgkozEXd9jAt4saniH5 HODL_redeemScript: 020008b175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\n" +
"HODL_depositAddress: 2N9vLAD9f1WqFiJXinC9oCxDhypz36ZzaT7 HODL_redeemScript: 028000b175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\n" +
"HODL_depositAddress: 2MxRBGmDkNK44wCw2NMNq12UKxuPmkN8Wrx HODL_redeemScript: 58b175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac\n";
var testOutput = "";
var saved = pushNetworkVars("btc-testnet");
var testName = "timelocks";
var timeLock = 0x80000000;
while (timeLock > 0) {
//var timeLock = Math.pow(2,n)-1;
//var timeLock = 16777215;
var wif = "cMahea7zqjxrtgAbB7LSGbcQUr1uX1ojuat9jZodMN87JcbXMTcA"; // TESTNET pubKey="0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", addr="mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r"
var pubkey = coinjs.wif2pubkey(wif);
var myHodl = coinjs.simpleHodlAddress(pubkey.pubkey, timeLock);
testOutput += 'HODL_depositAddress: ' + myHodl.address + ' ';
testOutput += 'HODL_redeemScript: ' + myHodl.redeemScript + '\n';
timeLock = (timeLock >>> 4);
}
popNetworkVars(saved);
addTestOutput(testName, testOutput, testExpected);
}
});
function addTestOutput(testName, testOutput, testExpected) {
var testResult = "Fail ❌";
if (testOutput == testExpected) { testResult = "Pass ✓"; }
document.getElementById('testResults').value += testName + " : " + testResult + "\n";
}
function popNetworkVars(saved) {
coinjs.pub = saved.pub;
coinjs.priv = saved.priv;
coinjs.multisig = saved.multisig;
}
function pushNetworkVars(network) {
var savedParams = {
'pub':coinjs.pub,
'priv':coinjs.priv,
'multisig':coinjs.multisig
};
if (network == "btc-mainnet") {
coinjs.pub = 0x00;
coinjs.priv = 0x80;
coinjs.multisig = 0x05;
}
if (network == "btc-testnet") {
coinjs.pub = 0x6f;
coinjs.priv = 0xef;
coinjs.multisig = 0xc4;
}
if (network == "ltc-mainnet") {
coinjs.pub = 0x30;
coinjs.priv = 0xb0;
coinjs.multisig = 0x32;
}
if (network == "ltc-testnet") {
coinjs.pub = 0x6f;
coinjs.priv = 0xef;
coinjs.multisig = 0x3a4;
}
if (network == "doge-mainnet") {
coinjs.pub = 0x1e;
coinjs.priv = 0x9e;
coinjs.multisig = 0x16;
}
return savedParams;
}
</script>
</html>