69 Commits

Author SHA1 Message Date
Kiyomichi Kosaka 6a6c2c6beb In verify for HD wallets add field to choose the address format. 2021-04-05 20:04:32 +02:00
OutCast3k 9a0175e18f added better error handling for when a payment fails on the #wallet page 2020-10-02 21:22:22 +00:00
OutCast3k 507b44f719 add transaction id reference to #newTransaction tab 2020-07-31 15:38:31 +00:00
OutCast3k c868cf984e bug fix, changes to make double spending work on the transaction page from a transction id 2020-07-31 15:17:30 +00:00
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
OutCast3k 44ba1b3d30 update readme 2019-12-25 22:15:55 +00:00
OutCast3k 5583675390 custom hd key derivation addded 2019-12-25 22:10:55 +00:00
OutCast3k 56cb104ea4 updated sha1sum 2019-12-24 23:01:50 +00:00
OutCast3k c6f70d000e Merge pull request #194 from jmacxx/fix_issue_140
fix Issue 140: error logged to console when switching tabs.
2019-12-24 23:00:22 +00:00
OutCast3k 4836b20fae updated sha1sum 2019-12-24 22:47:28 +00:00
OutCast3k f364ae4b4a Merge pull request #198 from jmacxx/fix_issue_193
fix: RBF always set when redeeming OP_CHECKLOCKTIMEVERIFY
2019-12-24 22:44:43 +00:00
OutCast3k 64cb387247 updated as outcast3k 2019-12-24 21:53:20 +00:00
btc b2a86006cf updated sha1sum file 2019-12-24 21:51:33 +00:00
OutCast3k b5ebaafed8 Merge pull request #202 from junderw/fixScriptNum
Fix script num
2019-12-24 21:49:03 +00:00
kinoshitajona d4f47fce28 Must do OPs with script method 2019-11-14 15:13:51 +09:00
kinoshitajona 5bd3786f94 Fix ScriptNum 2019-11-14 15:07:15 +09:00
Wowee0 b77f3cf06a fix: RBF always set when redeeming OP_CHECKLOCKTIMEVERIFY 2019-10-18 23:19:52 -05:00
Wowee0 b0c6c3a516 fix Uncaught TypeError logged to console when switching Tx Input and Output tabs 2019-09-23 21:01:03 -05:00
OutCast3k a6f5dcf7f0 removed debugger code 2019-09-22 20:32:42 +00:00
OutCast3k cf2a8b01cb update sha1sum file 2019-08-30 17:03:31 +00:00
OutCast3k 261c4ace40 Merge pull request #191 from Wowee0/choose_backend
fix for #189 .. three backend API options for btc/ltc/doge
2019-08-30 17:58:50 +01:00
Wowee0 e18b634c4e fix issue where empty broadcast did not handle the error response appropriately 2019-08-27 11:17:08 -05:00
Wowee0 1f3b878d63 bugfix for blockcypher when address used that has no UTXO 2019-08-22 07:41:36 -05:00
Wowee0 efc16c10fb allow backend API choice between blockcypher/blockchair/chain.so 2019-08-16 16:28:29 -05:00
Wowee0 477ca8890d Merge pull request #1 from OutCast3k/master
sync with OutCast3k/coinbin
2019-06-15 09:18:15 -05:00
OutCast3k e73e8093b3 change made to avoid captcha provided by cloudflare to TOR users 2019-06-05 19:34:45 +00:00
OutCast3k 40ea3230fd removed blockchain.com links 2019-05-28 15:21:58 +00:00
OutCast3k dc416c6521 changes made to paper wallet 2019-05-24 14:44:47 +00:00
OutCast3k fc66bc9423 Merge pull request #127 from olivergregorius/paperwallet
Paperwallet
2019-05-24 15:41:54 +01:00
OutCast3k 1c10bef510 Merge pull request #183 from yottalogical/blockchain-explorer-link
Add Link to Blockchain Explorer after Broadcasting Transaction (Litecoin)
2019-05-06 11:49:48 +01:00
yottalogical b22e79391f Update sha1sum 2019-05-05 12:36:32 -04:00
yottalogical 0be8fd9a97 Add link to blockchain explorer for Chain.so (Litecoin) 2019-05-05 12:30:28 -04:00
OutCast3k 1a364ff770 updated sha1sum file 2019-05-05 09:22:52 +00:00
OutCast3k bc0c72117e Merge pull request #182 from Wowee0/litecoin
re-enabled Litecoin
2019-05-05 10:11:31 +01:00
OutCast3k 13c50cf4b6 Merge pull request #170 from ivy-dong/ivy_remove_redundant_quotation_marks
remove redundant quotation marks
2019-05-05 10:09:08 +01:00
OutCast3k dea1d1b274 Merge pull request #178 from yottalogical/blockchain-explorer-link 2019-05-05 10:07:00 +01:00
Wowee0 e6c70d133b set appropriate hrp for Litecoin SegWit addresses
set chain.so/address/LTC for view of address (previously was referencing BTC block explorer)
2019-04-22 22:09:20 -05:00
Wowee0 10aa011c6e LTC SegWit (pre-bech32) address version changed from 5 to 50 (i.e. 3-addresses changed to M-addresses) 2019-04-20 23:28:40 -05:00
Wowee0 c7a0fda7e5 re-enabled Litecoin 2019-04-19 10:40:59 -05:00
yottalogical c9cfeefc86 Correct month in sha1sum 2019-02-22 18:19:35 -05:00
yottalogical cdf4aa105b Fix variable name in broadcast success message 2019-02-06 15:43:23 -05:00
yottalogical 2fc574dde0 Remove unnecessary linebreak at end 2019-02-06 15:34:25 -05:00
yottalogical f088ec2e52 Update sha1sum 2019-02-06 15:28:04 -05:00
yottalogical 9ccd73808d Capitalize TXID in success message 2019-02-06 15:23:09 -05:00
yottalogical cb81362330 Add link to blockchain explorer for Cryptoid.info (Carboncoin) 2019-02-06 15:21:39 -05:00
yottalogical fcbf25eaec Add link to blockchain explorer for coinb.in (Bitcoin) 2019-02-06 15:20:43 -05:00
yottalogical 2aca9ab28d Add link to blockchain explorer for Blockcypher.com 2019-02-06 14:46:19 -05:00
yottalogical 5c581316fe Add link to blockchain explorer for Chain.so (Bitcoin) 2019-02-06 14:39:48 -05:00
yottalogical ebfb940dd5 Fix typo in comment 2019-02-06 14:32:49 -05:00
yottalogical 3201550d40 Add link to blockchain explorer for Chain.so (Dogecoin) 2019-02-06 14:23:27 -05:00
OutCast3k d88ec3db4b update sha1sum file 2018-12-28 23:49:01 +00:00
OutCast3k 530453a701 improvement to previous timelock address bug fix 2018-12-28 23:42:00 +00:00
OutCast3k 194df37d56 bug fix for time locked addresses. transactions not being built correctly (no loss of funds!!!!) 2018-12-28 23:33:42 +00:00
Ivy Dong 87461b58b8 remove redundant quotation marks 2018-12-16 20:04:27 +08:00
OutCast3k 739aee3c0f couple of bug fixes with transaction building 2018-08-26 20:53:25 +00:00
oliverdorn b997751791 Added functionality for printing Paper Wallet 2017-11-25 00:53:00 +01:00
oliverdorn 9bccc5c512 Added Buttons for printing Paper Wallets
Added Buttons for printint Paper Wallets for generated Legacy- and SegWit-Adresses
2017-11-25 00:49:16 +01:00
6 changed files with 862 additions and 148 deletions
+9 -8
View File
@@ -1,7 +1,7 @@
coinbin
=======
A Open Source Browser Based Bitcoin Wallet. Version 1.4 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!
+67 -16
View File
@@ -338,7 +338,16 @@
</div>
<input type="button" class="btn btn-primary" value="Generate" id="newKeysBtn">
<div class="btn-group">
<input type="button" class="btn btn-primary" value="Generate" id="newKeysBtn">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a href="#" id="newPaperwalletBtn">Print</a></li>
</ul>
</div>
<br>
</div>
@@ -383,7 +392,17 @@
<input type="text" class="form-control hidden" id="brainwalletSegWit">
</div>
<input type="button" class="btn btn-primary" value="Generate" id="newSegWitKeysBtn">
<div class="btn-group">
<input type="button" class="btn btn-primary" value="Generate" id="newSegWitKeysBtn">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a href="#" id="newSegwitPaperwalletBtn">Print</a></li>
</ul>
</div>
<br>
</div>
@@ -578,7 +597,7 @@
<h2>Transaction <small>Create a new transaction</small></h2>
<p>Use this page to create a raw transaction</p>
<b>Address, WIF key or Redeem Script</b>:
<b>Address, WIF key, Redeem Script or Transaction ID</b>:
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-info qrcodeScanner" type="button" data-toggle="modal" data-target="#modalQrcodeScanner" forward-result="#redeemFrom"><span class="glyphicon glyphicon-camera"></span></button>
@@ -609,7 +628,7 @@
<label>Null Data</label> <span class="text-muted text-normal">(80 byte limit, <i>40 bytes recommended</i>)</span>
<p class="checkbox">
<label><input type="checkbox" id="opReturn" class="checkbox-inline"> Allow data to be sent within the transaction and stored in the blockchain by using <a href="https://bitcoin.org/en/developer-guide#null-data" target="_"blank">OP_RETURN</a>.</label>
<label><input type="checkbox" id="opReturn" class="checkbox-inline"> Allow data to be sent within the transaction and stored in the blockchain by using <a href="https://bitcoin.org/en/developer-guide#null-data" target="_blank">OP_RETURN</a>.</label>
<div class="text-muted">When using this option you may enter a hex string or address into the address field on the output tab.</div>
</p>
@@ -624,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>
@@ -1172,23 +1191,40 @@
<p>The path of key derivation</p>
<div class="row">
<div class="col-md-8">
<div class="col-md-6">
<b>Path</b><br>
<select class="form-control">
<option>Simple: m/i</option>
<select class="form-control" id="hdpathtype"">
<option value="simple">Simple: m/i</option>
<option value="custom">Custom</option>
</select>
<div id="hdpath" class="hidden" style="margin-top:4px">
<span class="input-group">
<input type="text" class="form-control" value="m/0/1"> <br>
<span class="input-group-addon"> / </span>
</span>
</div>
</div>
<div class="col-md-2">
<b>Index (Start)</b><br>
<b><u>I</u>ndex (Start)</b><br>
<input type="text" class="form-control derivation_index_start" value="0">
</div>
<div class="col-md-2">
<b>Index (End)</b><br>
<b><u>I</u>ndex (End)</b><br>
<input type="text" class="form-control derivation_index_end" value="1">
</div>
<div class="col-md-2">
<b>Address format</b><br>
<select class="form-control derivation_addr_format">
<option value="bech32">Bech32</option>
<option value="segwit">SegWit</option>
<option value="legacy">Legacy</option>
</select>
</div>
</div>
<hr>
@@ -1199,7 +1235,7 @@
<div class="derived_data">
<table class="table table-striped table-hover">
<thead>
<tr><td><b>Index</b></td><td><b>Address</b><td><b>Private Key (WIF)</b></td></td><td><b>Extended xPub</b></td><td><b>Extended xPrv</b></td></tr>
<tr><td><b>Index</b></td><td><b>Address</b></td><td><b>Redeem script</b></td><td><b>Private Key (WIF)</b></td><td><b>Extended xPub</b></td><td><b>Extended xPrv</b></td></tr>
</thead>
<tbody>
</tbody>
@@ -1306,7 +1342,7 @@
<div class="tab-pane tab-content" id="about">
<h2>About <small>open source bitcoin wallet</small></h2>
<p>Version 1.4</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>
@@ -1316,12 +1352,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">
@@ -1334,7 +1371,8 @@
<p class="text-muted">Select which network you'd like to use for key pair generation.</p>
<select class="form-control" id="coinjs_coin">
<option value="bitcoin_mainnet" rel="0x00;0x80;0x05;0x488b21e;0x488ade4;coinb.in;coinb.in">Bitcoin (mainnet)</option>
<option value="dogecoin_mainnet" rel="0x1e;0x9e;0x16;0x0827421e;0x089944e4;chain.so_dogecoin;chain.so_dogecoin">Dogecoin (mainnet)</option>
<option value="litecoin_mainnet" rel="0x30;0xb0;0x32;0x019da462;0x019d9cfe;blockcypher_litecoin;blockcypher_litecoin">Litecoin (mainnet)</option>
<option value="dogecoin_mainnet" rel="0x1e;0x9e;0x16;0x0827421e;0x089944e4;blockcypher_dogecoin;blockcypher_dogecoin">Dogecoin (mainnet)</option>
<option value="carboncoin_mainnet" rel="0x2f;0xaf;0x05;0x488b21e;0x488ade4;cryptoid.info_carboncoin;cryptoid.info_carboncoin">Carboncoin (mainnet)</option>
<option value="shadowcash_mainnet" rel="0x3f;0xbf;0x7d;0xee80286a;0xee8031e8;false;false">ShadowCash (mainnet)</option>
<option value="bitcoin_testnet" rel="0x6f;0xef;0xc4;0x043587cf;0x04358394;false;false">Bitcoin (testnet)</option>
@@ -1391,8 +1429,14 @@
<p class="text-muted">Select the network you wish to broadcast the transaction via</p>
<select class="form-control" id="coinjs_broadcast">
<option value="coinb.in">coinb.in (Bitcoin mainnet)</option>
<option value="chain.so_bitcoinmainnet"> Chain.so (Bitcoin mainnet)</option>
<option value="blockcypher_bitcoinmainnet"> Blockcypher.com (Bitcoin mainnet)</option>
<option value="blockcypher_litecoin"> Blockcypher.com (Litecoin)</option>
<option value="blockcypher_dogecoin"> Blockcypher.com (Dogecoin)</option>
<option value="blockchair_bitcoinmainnet"> Blockchair.com (Bitcoin mainnet)</option>
<option value="blockchair_litecoin"> Blockchair.com (Litecoin)</option>
<option value="blockchair_dogecoin"> Blockchair.com (Dogecoin)</option>
<option value="chain.so_bitcoinmainnet"> Chain.so (Bitcoin mainnet)</option>
<option value="chain.so_litecoin"> Chain.so (Litecoin)</option>
<option value="chain.so_dogecoin"> Chain.so (Dogecoin)</option>
<option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option>
</select>
@@ -1407,6 +1451,13 @@
<p class="text-muted">Select the network you wish to retreive your unspent inputs from</p>
<select class="form-control" id="coinjs_utxo">
<option value="coinb.in">coinb.in (Bitcoin mainnet)</option>
<option value="blockcypher_bitcoinmainnet"> Blockcypher.com (Bitcoin mainnet)</option>
<option value="blockcypher_litecoin"> Blockcypher.com (Litecoin)</option>
<option value="blockcypher_dogecoin"> Blockcypher.com (Dogecoin)</option>
<option value="blockchair_bitcoinmainnet"> Blockchair.com (Bitcoin mainnet)</option>
<option value="blockchair_litecoin"> Blockchair.com (Litecoin)</option>
<option value="blockchair_dogecoin"> Blockchair.com (Dogecoin)</option>
<option value="chain.so_bitcoinmainnet"> Chain.so (Bitcoin mainnet)</option>
<option value="chain.so_litecoin"> Chain.so (Litecoin)</option>
<option value="chain.so_dogecoin"> Chain.so (Dogecoin)</option>
<option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option>
@@ -1433,7 +1484,7 @@
<div id="footer">
<div class="container text-right">
<p class="text-muted">Version 1.4</p>
<p class="text-muted">Version 1.6</p>
</div>
</div>
+136 -38
View File
@@ -19,10 +19,11 @@
coinjs.compressed = false;
/* other vars */
coinjs.developer = '3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN'; //bitcoin
coinjs.developer = '33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G'; //bitcoin
/* bit(coinb.in) api vars */
coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+'coinb.in/api/';
coinjs.hostname = ((document.location.hostname.split(".")[(document.location.hostname.split(".")).length-1]) == 'onion') ? '4zpinp6gdkjfplhk.onion' : 'coinb.in';
coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+coinjs.hostname+'/api/';
coinjs.uid = '1';
coinjs.key = '12345678901234567890123456789012';
@@ -155,7 +156,11 @@
}
var s = coinjs.script();
s.writeBytes(coinjs.numToByteArray(checklocktimeverify));
if (checklocktimeverify <= 16 && checklocktimeverify >= 1) {
s.writeOp(0x50 + checklocktimeverify);//OP_1 to OP_16 for minimal encoding
} else {
s.writeBytes(coinjs.numToScriptNumBytes(checklocktimeverify));
}
s.writeOp(177);//OP_CHECKLOCKTIMEVERIFY
s.writeOp(117);//OP_DROP
s.writeBytes(Crypto.util.hexToBytes(pubkey));
@@ -198,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;
}
@@ -302,7 +307,7 @@
return o;
} else {
return false;
throw "Invalid checksum";
}
} catch(e) {
bech32rs = coinjs.bech32redeemscript(addr);
@@ -613,10 +618,20 @@
var privkey = (r.key_bytes).slice(1, 33);
var privkeyHex = Crypto.util.bytesToHex(privkey);
var pubkey = coinjs.newPubkey(privkeyHex);
var addr_format = $("#verifyHDaddress .derivation_addr_format").val();
if (addr_format == "bech32") {
var address = coinjs.bech32Address(pubkey);
} else if (addr_format == "segwit") {
var address = coinjs.segwitAddress(pubkey);
} else {
var address = {'address': coinjs.pubkey2address(pubkey),
'redeemscript': ''};
}
r.keys = {'privkey':privkeyHex,
'pubkey':pubkey,
'address':coinjs.pubkey2address(pubkey),
'address':address.address,
'script':address.redeemscript,
'wif':coinjs.privkey2wif(privkeyHex)};
} else if(r.key_bytes[0] == 0x02 || r.key_bytes[0] == 0x03) {
@@ -633,6 +648,8 @@
coinjs.compressed = c; // reset to default
}
return r;
}
// extend prv/pub key
@@ -646,8 +663,37 @@
'pubkey':this.keys.pubkey});
}
// derive from path
r.derive_path = function(path) {
if( path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'' ) return this;
var p = path.split('/');
var hdp = coinjs.clone(this); // clone hd path
for( var i in p ) {
if((( i == 0 ) && c != 'm') || i == 'remove'){
continue;
}
var c = p[i];
var use_private = (c.length > 1) && (c[c.length-1] == '\'');
var child_index = parseInt(use_private ? c.slice(0, c.length - 1) : c) & 0x7fffffff;
if(use_private)
child_index += 0x80000000;
hdp = hdp.derive(child_index);
var key = ((hdp.keys_extended.privkey) && hdp.keys_extended.privkey!='') ? hdp.keys_extended.privkey : hdp.keys_extended.pubkey;
hdp = coinjs.hd(key);
}
return hdp;
}
// derive key from index
r.derive = function(i){
i = (i)?i:0;
var blob = (Crypto.util.hexToBytes(this.keys.pubkey)).concat(coinjs.numToBytes(i,4).reverse());
@@ -660,23 +706,34 @@
var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
var curve = ecparams.getCurve();
var k, key, pubkey, o;
var k, key, pubkey, o, addr_format, address_fun, address;
o = coinjs.clone(this);
o.chain_code = ir;
o.child_index = i;
addr_format = $("#verifyHDaddress .derivation_addr_format").val();
if (addr_format == "bech32") {
address_fun = function(pk) { return coinjs.bech32Address(pk); };
} else if (addr_format == "segwit") {
address_fun = function(pk) { return coinjs.segwitAddress(pk); };
} else {
address_fun = function(pk) {
return {'address': coinjs.pubkey2address(pk), 'redeemscript': ''};
};
}
if(this.type=='private'){
// derive key pair from from a xprv key
k = il.add(new BigInteger([0].concat(Crypto.util.hexToBytes(this.keys.privkey)))).mod(ecparams.getN());
key = Crypto.util.bytesToHex(k.toByteArrayUnsigned());
pubkey = coinjs.newPubkey(key);
address = address_fun(pubkey);
o.keys = {'privkey':key,
'pubkey':pubkey,
'wif':coinjs.privkey2wif(key),
'address':coinjs.pubkey2address(pubkey)};
'address':address.address,
'script':address.redeemscript};
} else if (this.type=='public'){
// derive xpub key from an xpub key
@@ -693,16 +750,17 @@
publicKeyBytesCompressed.unshift(0x03)
}
pubkey = Crypto.util.bytesToHex(publicKeyBytesCompressed);
address = address_fun(pubkey);
o.keys = {'pubkey':pubkey,
'address':coinjs.pubkey2address(pubkey)}
'address':address.address,
'script':address.redeemscript}
} else {
// fail
}
o.parent_fingerprint = (ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(r.keys.pubkey),{asBytes:true}),{asBytes:true})).slice(0,4);
o.keys_extended = o.extend();
return o;
}
@@ -767,8 +825,7 @@
return o;
}
r.parse();
return r;
return r.parse();
}
@@ -846,6 +903,9 @@
var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired);
r.address = multi['address'];
r.type = 'multisig__'; // using __ for now to differentiat from the other object .type == "multisig"
var rs = Crypto.util.bytesToHex(s.buffer);
r.redeemscript = rs;
} else if((s.chunks.length==2) && (s.buffer[0] == 0 && s.buffer[1] == 20)){ // SEGWIT
r = {};
r.type = "segwit__";
@@ -859,6 +919,8 @@
r.pubkey = Crypto.util.bytesToHex(s.chunks[3]);
r.checklocktimeverify = coinjs.bytesToNum(s.chunks[0].slice());
r.address = coinjs.simpleHodlAddress(r.pubkey, r.checklocktimeverify).address;
var rs = Crypto.util.bytesToHex(s.buffer);
r.redeemscript = rs;
r.type = "hodl__";
}
} catch(e) {
@@ -1028,6 +1090,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;
@@ -1048,32 +1115,37 @@
var unspent = xmlDoc.getElementsByTagName("unspent")[0];
for(i=1;i<=unspent.childElementCount;i++){
var u = xmlDoc.getElementsByTagName("unspent_"+i)[0]
var txhash = (u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue).match(/.{1,2}/g).reverse().join("")+'';
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
if(unspent){
for(i=1;i<=unspent.childElementCount;i++){
var u = xmlDoc.getElementsByTagName("unspent_"+i)[0]
var txhash = (u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue).match(/.{1,2}/g).reverse().join("")+'';
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
if(segwit){
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
It is not standard and removed during the signing procedure. */
if(segwit){
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
It is not standard and removed during the signing procedure. */
s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(script));
s.writeOp(0);
s.writeBytes(coinjs.numToBytes(u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1, 8));
scr = Crypto.util.bytesToHex(s.buffer);
s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(script));
s.writeOp(0);
s.writeBytes(coinjs.numToBytes(u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1, 8));
scr = Crypto.util.bytesToHex(s.buffer);
}
var seq = sequence || false;
self.addinput(txhash, n, scr, seq);
value += u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1;
total++;
}
var seq = sequence || false;
self.addinput(txhash, n, scr, seq);
value += u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1;
total++;
}
x.unspent = $(xmlDoc).find("unspent");
x.result = xmlDoc.getElementsByTagName("result")[0].childNodes[0].nodeValue;
x.unspent = unspent;
x.value = value;
x.total = total;
x.response = xmlDoc.getElementsByTagName("response")[0].childNodes[0].nodeValue;
return callback(x);
});
}
@@ -1297,7 +1369,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)};
@@ -1918,12 +1997,31 @@
}
}
coinjs.numToByteArray = function(num) {
if (num <= 256) {
return [num];
} else {
return [num % 256].concat(coinjs.numToByteArray(Math.floor(num / 256)));
function scriptNumSize(i) {
return i > 0x7fffffff ? 5
: i > 0x7fffff ? 4
: i > 0x7fff ? 3
: i > 0x7f ? 2
: i > 0x00 ? 1
: 0;
}
coinjs.numToScriptNumBytes = function(_number) {
var value = Math.abs(_number);
var size = scriptNumSize(value);
var result = [];
for (var i = 0; i < size; ++i) {
result.push(0);
}
var negative = _number < 0;
for (i = 0; i < size; ++i) {
result[i] = value & 0xff;
value = Math.floor(value / 256);
}
if (negative) {
result[size - 1] |= 0x80;
}
return result;
}
coinjs.numToVarInt = function(num) {
+265 -81
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();
});
@@ -171,7 +170,7 @@ $(document).ready(function() {
script = sw.redeemscript;
}
var sequence = false;
var sequence = 0xffffffff-1;
if($("#walletRBF").is(":checked")){
sequence = 0xffffffff-2;
}
@@ -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 */
@@ -344,7 +335,22 @@ $(document).ready(function() {
$("#aes256passStatus").removeClass("hidden");
}
$("#newPrivKeyEnc").val(CryptoJS.AES.encrypt(coin.wif, $("#aes256pass").val())+'');
});
$("#newPaperwalletBtn").click(function(){
if($("#newBitcoinAddress").val()==""){
$("#newKeysBtn").click();
}
var paperwallet = window.open();
paperwallet.document.write('<h2>BTC PaperWallet</h2><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Address (Share)</h3></div><div style="text-align: center;"><div id="qraddress"></div><p>'+$("#newBitcoinAddress").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Public Key</h3></div><div style="text-align: center;"><div id="qrpubkey"></div><p>'+$("#newPubKey").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Private Key (KEEP SECRET!)</h3></div><div style="text-align: center;"><div id="qrprivkey"></div><p>'+$("#newPrivKey").val()+'</p></div></div>');
paperwallet.document.close();
paperwallet.focus();
new QRCode(paperwallet.document.getElementById("qraddress"), {text: $("#newBitcoinAddress").val(), width: 125, height: 125});
new QRCode(paperwallet.document.getElementById("qrpubkey"), {text: $("#newPubKey").val(), width: 125, height: 125});
new QRCode(paperwallet.document.getElementById("qrprivkey"), {text: $("#newPrivKey").val(), width: 125, height: 125});
paperwallet.print();
paperwallet.close();
});
$("#newBrainwallet").click(function(){
@@ -392,6 +398,22 @@ $(document).ready(function() {
coinjs.compressed = compressed;
});
$("#newSegwitPaperwalletBtn").click(function(){
if($("#newSegWitAddress").val()==""){
$("#newSegWitKeysBtn").click();
}
var paperwallet = window.open();
paperwallet.document.write('<h2>BTC SegWit PaperWallet</h2><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Address (Share)</h3></div><div style="text-align: center;"><div id="qraddress"></div><p>'+$("#newSegWitAddress").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Public Key</h3></div><div style="text-align: center;"><div id="qrpubkey"></div><p>'+$("#newSegWitPubKey").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Redeem Script</h3></div><div style="text-align: center;"><div id="qrredeem"></div><p>'+$("#newSegWitRedeemScript").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Private Key (KEEP SECRET!)</h3></div><div style="text-align: center;"><div id="qrprivkey"></div><p>'+$("#newSegWitPrivKey").val()+'</p></div></div>');
paperwallet.document.close();
paperwallet.focus();
new QRCode(paperwallet.document.getElementById("qraddress"), {text: $("#newSegWitAddress").val(), width: 110, height: 110});
new QRCode(paperwallet.document.getElementById("qrpubkey"), {text: $("#newSegWitPubKey").val(), width: 110, height: 110});
new QRCode(paperwallet.document.getElementById("qrredeem"), {text: $("#newSegWitRedeemScript").val(), width: 110, height: 110});
new QRCode(paperwallet.document.getElementById("qrprivkey"), {text: $("#newSegWitPrivKey").val(), width: 110, height: 110});
paperwallet.print();
paperwallet.close();
});
/* new -> multisig code */
@@ -625,7 +647,7 @@ $(document).ready(function() {
}
if(!$(o).hasClass("has-error")){
var seq = null;
var seq = 0xffffffff-1;
if($("#txRBF").is(":checked")){
seq = 0xffffffff-2;
}
@@ -854,12 +876,12 @@ $(document).ready(function() {
/* redeem from button code */
$("#redeemFromBtn").click(function(){
var redeem = redeemingFrom($("#redeemFrom").val());
var redeem = redeemingFrom($("#redeemFrom").val());
$("#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;
}
@@ -876,11 +898,32 @@ $(document).ready(function() {
var host = $(this).attr('rel');
// api: blockcypher blockchair chain.so
// network name "btc" "bitcoin" "BTC"
// network name "ltc" "litecoin" "LTC"
// network name "doge" "dogecoin" "DOGE"
if(host=='chain.so_litecoin'){
listUnspentChainso_Litecoin(redeem);
if(host=='chain.so_bitcoinmainnet'){
listUnspentChainso(redeem, "BTC");
} else if(host=='chain.so_litecoin'){
listUnspentChainso(redeem, "LTC");
} else if(host=='chain.so_dogecoin'){
listUnspentChainso_Dogecoin(redeem);
listUnspentChainso(redeem, "DOGE");
} else if(host=='blockcypher_bitcoinmainnet'){
listUnspentBlockcypher(redeem, "btc");
} else if(host=='blockcypher_litecoin'){
listUnspentBlockcypher(redeem, "ltc");
} else if(host=='blockcypher_dogecoin'){
listUnspentBlockcypher(redeem, "doge");
} else if(host=='blockchair_bitcoinmainnet'){
listUnspentBlockchair(redeem, "bitcoin");
} else if(host=='blockchair_litecoin'){
listUnspentBlockchair(redeem, "litecoin");
} else if(host=='blockchair_dogecoin'){
listUnspentBlockchair(redeem, "dogecoin");
} else if(host=='cryptoid.info_carboncoin'){
listUnspentCryptoidinfo_Carboncoin(redeem);
} else {
@@ -889,8 +932,8 @@ $(document).ready(function() {
if($("#redeemFromStatus").hasClass("hidden")) {
// An ethical dilemma: Should we automatically set nLockTime?
if(redeem.from == 'redeemScript' && redeem.decodedRs.type == "hodl__") {
$("#nLockTime").val(redeem.decodedRs.checklocktimeverify);
if(redeem.from == 'redeemScript' && redeem.type == "hodl__") {
$("#nLockTime").val(redeem.decodescript.checklocktimeverify);
} else {
$("#nLockTime").val(0);
}
@@ -926,11 +969,19 @@ $(document).ready(function() {
r.addr = decodeRs['address'];
r.from = 'redeemScript';
r.decodedRs = decodeRs.redeemscript;
r.type = decodeRs['type'];
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;
@@ -997,9 +1048,59 @@ $(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 scr = $(o).find("script").text();
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>');
@@ -1022,25 +1123,27 @@ $(document).ready(function() {
}
/* retrieve unspent data from chainso for litecoin */
function listUnspentChainso_Litecoin(redeem){
/* retrieve unspent data from blockcypher */
function listUnspentBlockcypher(redeem,network){
$.ajax ({
type: "GET",
url: "https://chain.so/api/v2/get_tx_unspent/ltc/"+redeem.addr,
url: "https://api.blockcypher.com/v1/"+network+"/main/addrs/"+redeem.addr+"?includeScript=true&unspentOnly=true",
dataType: "json",
error: function(data) {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
},
success: function(data) {
if((data.status && data.data) && data.status=='success'){
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>');
for(var i in data.data.txs){
var o = data.data.txs[i];
var tx = ((o.txid).match(/.{1,2}/g).reverse()).join("")+'';
var n = o.output_no;
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o.script_hex;
var amount = o.value;
addOutput(tx, n, script, amount);
for(var i in data.txrefs){
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;
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o.script;
var amount = ((o.value.toString()*1)/100000000).toFixed(8);
addOutput(tx, n, script, amount);
}
}
} else {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.');
@@ -1087,19 +1190,54 @@ $(document).ready(function() {
}
/* retrieve unspent data from chain.so for dogecoin */
function listUnspentChainso_Dogecoin(redeem){
/* retrieve unspent data from blockchair */
function listUnspentBlockchair(redeem,network){
$.ajax ({
type: "GET",
url: "https://chain.so/api/v2/get_tx_unspent/doge/"+redeem.addr,
url: "https://api.blockchair.com/"+network+"/dashboards/address/"+redeem.addr,
dataType: "json",
error: function(data) {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
},
success: function(data) {
if((data.context && data.data) && data.context.code =='200'){
$("#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>');
var all_info = data.data[redeem.addr];
for(var i in all_info.utxo){
var o = all_info.utxo[i];
var tx = ((""+o.transaction_hash).match(/.{1,2}/g).reverse()).join("")+'';
if(tx.match(/^[a-f0-9]+$/)){
var n = o.index;
var script = (redeem.redeemscript==true) ? redeem.decodedRs : all_info.address.script_hex;
var amount = ((o.value.toString()*1)/100000000).toFixed(8);
addOutput(tx, n, script, amount);
}
}
} else {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.');
}
},
complete: function(data, status) {
$("#redeemFromBtn").html("Load").attr('disabled',false);
totalInputAmount();
}
});
}
/* retrieve unspent data from chainso */
function listUnspentChainso(redeem, network){
$.ajax ({
type: "GET",
url: "https://chain.so/api/v2/get_tx_unspent/"+network+"/"+redeem.addr,
dataType: "json",
error: function(data) {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
},
success: function(data) {
if((data.status && data.data) && data.status=='success'){
$("#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.data.txs){
var o = data.data.txs[i];
var tx = ((""+o.txid).match(/.{1,2}/g).reverse()).join("")+'';
@@ -1121,6 +1259,7 @@ $(document).ready(function() {
});
}
/* math to calculate the inputs and outputs */
function totalInputAmount(){
@@ -1180,7 +1319,7 @@ $(document).ready(function() {
rawSubmitDefault(this);
});
// broadcast transaction vai coinbin (default)
// broadcast transaction via coinbin (default)
function rawSubmitDefault(btn){
var thisbtn = btn;
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
@@ -1195,8 +1334,7 @@ $(document).ready(function() {
success: function(data) {
$("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden');
if($(data).find("result").text()==1){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger');
$("#rawTransactionStatus").html('txid: '+$(data).find("txid").text());
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' TXID: ' + $(data).find("txid").text() + '<br> <a href="https://coinb.in/tx/' + $(data).find("txid").text() + '" target="_blank">View on Blockchain</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
}
@@ -1222,8 +1360,7 @@ $(document).ready(function() {
success: function(data) {
$("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden');
if($(data).find("result").text()==1){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger');
$("#rawTransactionStatus").html('txid: '+$(data).find("txid").text());
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' TXID: ' + $(data).find("txid").text() + '<br> <a href="https://chainz.cryptoid.info/carbon/tx.dws?' + $(data).find("txid").text() + '" target="_blank">View on Blockchain Explorer</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
}
@@ -1236,11 +1373,11 @@ $(document).ready(function() {
}
// broadcast transaction via chain.so (mainnet)
function rawSubmitChainso_BitcoinMainnet(thisbtn){
function rawSubmitChainso(thisbtn, network){
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://chain.so/api/v2/send_tx/BTC/",
url: "https://chain.so/api/v2/send_tx/"+network+"/",
data: {"tx_hex":$("#rawTransaction").val()},
dataType: "json",
error: function(data) {
@@ -1252,7 +1389,7 @@ $(document).ready(function() {
},
success: function(data) {
if(data.status && data.data.txid){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.data.txid);
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' TXID: ' + data.data.txid + '<br> <a href="https://chain.so/tx/'+network+'/' + data.data.txid + '" target="_blank">View on Blockchain Explorer</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
@@ -1265,22 +1402,20 @@ $(document).ready(function() {
}
// broadcast transaction via blockcypher.com (mainnet)
function rawSubmitblockcypher_BitcoinMainnet(thisbtn){
function rawSubmitblockcypher(thisbtn, network){
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://api.blockcypher.com/v1/btc/main/txs/push",
url: "https://api.blockcypher.com/v1/"+network+"/main/txs/push",
data: JSON.stringify({"tx":$("#rawTransaction").val()}),
error: function(data) {
var obj = $.parseJSON(data.responseText);
var r = ' ';
r += (obj.error) ? obj.error : '';
r = (r!='') ? r : ' Failed to broadcast'; // build response
var r = 'Failed to broadcast: error code=' + data.status.toString() + ' ' + data.statusText;
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
},
success: function(data) {
if((data.tx) && data.tx.hash){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.tx.hash);
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden")
.html(' TXID: ' + data.tx.hash + '<br> <a href="https://live.blockcypher.com/'+network+'/tx/' + data.tx.hash + '" target="_blank">View on Blockchain Explorer</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
@@ -1292,27 +1427,24 @@ $(document).ready(function() {
});
}
// broadcast transaction via chain.so for dogecoin
function rawSubmitchainso_dogecoin(thisbtn){
// broadcast transaction via blockchair
function rawSubmitblockchair(thisbtn, network){
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://chain.so/api/v2/send_tx/DOGE",
data: {"tx_hex":$("#rawTransaction").val()},
url: "https://api.blockchair.com/"+network+"/push/transaction",
data: {"data":$("#rawTransaction").val()},
dataType: "json",
error: function(data) {
var obj = $.parseJSON(data.responseText);
var r = ' ';
r += (obj.data.tx_hex) ? ' '+obj.data.tx_hex : '';
r = (r!='') ? r : ' Failed to broadcast'; // build response
var r = 'Failed to broadcast: error code=' + data.status.toString() + ' ' + data.statusText;
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
// console.error(JSON.stringify(data, null, 4));
},
success: function(data) {
// console.info(JSON.stringify(data, null, 4));
if((data.status && data.data) && data.status=='success'){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: ' + data.data.txid);
if((data.context && data.data) && data.context.code=='200'){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden")
.html(' TXID: ' + data.data.transaction_hash + '<br> <a href="https://blockchair.com/'+network+'/transaction/' + data.data.transaction_hash + '" target="_blank">View on Blockchain Explorer</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
@@ -1574,10 +1706,15 @@ $(document).ready(function() {
var html = '';
$("#verifyHDaddress .derived_data table tbody").html("");
for(var i=index_start;i<=index_end;i++){
var derived = hd.derive(i);
if($("#hdpathtype option:selected").val()=='simple'){
var derived = hd.derive(i);
} else {
var derived = hd.derive_path(($("#hdpath input").val().replace(/\/+$/, ""))+'/'+i);
}
html += '<tr>';
html += '<td>'+i+'</td>';
html += '<td><input type="text" class="form-control" value="'+derived.keys.address+'" readonly></td>';
html += '<td><input type="text" class="form-control" value="'+derived.keys.script+'" readonly></td>';
html += '<td><input type="text" class="form-control" value="'+((derived.keys.wif)?derived.keys.wif:'')+'" readonly></td>';
html += '<td><input type="text" class="form-control" value="'+derived.keys_extended.pubkey+'" readonly></td>';
html += '<td><input type="text" class="form-control" value="'+((derived.keys_extended.privkey)?derived.keys_extended.privkey:'')+'" readonly></td>';
@@ -1587,6 +1724,15 @@ $(document).ready(function() {
}
$("#hdpathtype").change(function(){
if($(this).val()=='simple'){
$("#hdpath").removeClass().addClass("hidden");
} else {
$("#hdpath").removeClass();
}
});
/* sign code */
$("#signBtn").click(function(){
@@ -1717,7 +1863,7 @@ $(document).ready(function() {
$('a[data-toggle="tab"]').on('click', function(e) {
e.preventDefault();
if(e.target){
if(e.target && $(e.target).attr('href')) {
history.pushState(null, null, '#'+$(e.target).attr('href').substr(1));
}
});
@@ -1772,6 +1918,14 @@ $(document).ready(function() {
configureBroadcast();
configureGetUnspentTx();
if (coinjs.pub == 0x30){ // LTC
explorer_addr = "https://chain.so/address/LTC/";
coinjs.bech32.hrp = "ltc";
}
else if (coinjs.pub == 0x1e){ // DOGE
explorer_addr = "https://chain.so/address/DOGE/";
}
$("#statusSettings").addClass("alert-success").removeClass("hidden").html("<span class=\"glyphicon glyphicon-ok\"></span> Settings updates successfully").fadeOut().fadeIn();
} else {
$("#statusSettings").addClass("alert-danger").removeClass("hidden").html("There is an error with one or more of your settings");
@@ -1817,18 +1971,48 @@ $(document).ready(function() {
function configureBroadcast(){
var host = $("#coinjs_broadcast option:selected").val();
// api: blockcypher blockchair chain.so
// network name "btc" "bitcoin" "BTC"
// network name "ltc" "litecoin" "LTC"
// network name "doge" "dogecoin" "DOGE"
$("#rawSubmitBtn").unbind("");
if(host=="chain.so_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){
rawSubmitChainso_BitcoinMainnet(this);
rawSubmitChainso(this, "BTC");
});
} else if(host=="chain.so_litecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitchainso(this, "LTC");
});
} else if(host=="chain.so_dogecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitchainso_dogecoin(this);
rawSubmitchainso(this, "DOGE");
});
} else if(host=="blockcypher_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockcypher_BitcoinMainnet(this);
rawSubmitblockcypher(this, "btc");
});
} else if(host=="blockcypher_litecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockcypher(this, "ltc");
});
} else if(host=="blockcypher_dogecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockcypher(this, "doge");
});
} else if(host=="blockchair_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockchair(this, "bitcoin");
});
} else if(host=="blockchair_litecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockchair(this, "litecoin");
});
} else if(host=="blockchair_dogecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockchair(this, "dogecoin");
});
} else if(host=="cryptoid.info_carboncoin"){
$("#rawSubmitBtn").click(function(){
+6 -5
View File
@@ -1,9 +1,9 @@
---- Version 1.4 2018.06.19 ---
---- Version 1.6 2020.10.02 ----
77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js
3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js
253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js
988f99187ab356bc5d12b61572f463e1785c15c2 ./js/coinbin.js
8b4163122d907f9c363b9afd8809490f5ba202c8 ./js/coin.js
cb5717166bf1c99abbd75a06013067c4a5897d5a ./js/coinbin.js
911fb7bdba24269029f27659e4040cd991b2307c ./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
c024021c71cba503979a859d23cbf7a88b570d82 ./README.md
26552aac02a06e88b419539f93032de8a25e1edd ./index.html
ee481606d8d48f402d152fa632ba9e5f9da7f169 ./README.md
a706e95f6436ee4a31dc26b17a9ac8ab1f0d3750 ./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>