87 Commits

Author SHA1 Message Date
Kiyomichi Kosaka cea94af32f Make custom field visible automatically after refresh. 2021-04-07 17:33:49 +02:00
Kiyomichi Kosaka 3b1e44e4b4 Merge branch 'master' into full_featured 2021-04-05 20:20:13 +02:00
Kiyomichi Kosaka 06054a7000 Merge branch 'hdwallet_bech32' into full_featured 2021-04-05 20:06:40 +02:00
Kiyomichi Kosaka 6a6c2c6beb In verify for HD wallets add field to choose the address format. 2021-04-05 20:04:32 +02:00
Kiyomichi Kosaka 04609947e8 Merge branch 'hdwallet_bech32' into full_featured 2021-04-05 19:58:57 +02:00
Kiyomichi Kosaka 40a235eb04 Fix address generation for HD wallet with different types on simple path scheme. 2021-04-05 19:58:35 +02:00
Kiyomichi Kosaka 20bf365d29 Merge branch 'hdwallet_bech32' into full_featured 2021-04-05 19:37:54 +02:00
Kiyomichi Kosaka 632572fc66 Merge branch 'hd_wallet_seed' into full_featured 2021-04-05 19:37:39 +02:00
Kiyomichi Kosaka 00519cb2ab Add possibility in verify view for HD wallets to choose the address format. 2021-04-05 19:03:02 +02:00
Kiyomichi Kosaka 2b6de3edef Use HMAC SHA-256 with configurable amount of rounds to generate seed for HD wallet, also show the generated seed in WIF format. 2021-04-05 18:15:33 +02:00
Kiyomichi Kosaka f408c9b251 Add the posibility to specify hardened indicies on HD wallets. 2021-04-05 13:48:21 +02:00
Kiyomichi Kosaka bd82cfd76f Add tooltip to custom path field and make names in HD wallet setting a bit more precise. 2021-04-05 13:48:21 +02:00
Kiyomichi Kosaka 27a2d4efb1 Add setting to configure old HD wallet generation with hardened paths. 2021-04-05 13:48:08 +02:00
Kiyomichi Kosaka 704f2c96a3 Fix the derivation of the hd wallet hardened path to be BIP32 compliant. 2021-04-05 13:10:41 +02:00
Kiyomichi Kosaka 29baeff8c8 Fix small typo. 2021-04-05 13:07:27 +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
OutCast3k fd81fafdff segwit signing bug fix 2018-06-19 15:45:21 +00:00
OutCast3k 9bede2aef4 Update sha1sum 2018-06-17 11:37:21 +01:00
OutCast3k 37f4395d9f wallet segwit spend bugfix 2018-06-17 09:22:44 +00:00
OutCast3k 5a65a77bd2 added a bech32 address to the #wallet section of coinb.in 2018-06-11 16:23:18 +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 995 additions and 175 deletions
+9 -8
View File
@@ -1,7 +1,7 @@
coinbin 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 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. - Brain wallet support.
- Compatible with bitcoin-qt - Compatible with bitcoin-qt
- An offical .onion address for tor users. - An offical .onion address for tor users.
- Offline qrcode creator and scanning tool - Offline qrcode creator and scanning tool.
- HD (bip32) support - HD (bip32) support.
- Supports altcoins such as litecoin - Supports altcoins such as litecoin.
- Replace by fee (RBF) Support - Replace by fee (RBF) Support.
- Segwit Support - Segwit Support.
- Bech32 address support - Bech32 address support.
- Fee calculator - https://coinb.in/#fees - 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!
+101 -19
View File
@@ -158,7 +158,9 @@
<div class="hidden optionsAdvanced"> <div class="hidden optionsAdvanced">
<label>Segregated Witness Address</label> <label>Segregated Witness Address</label>
<p class="checkbox"> <p class="checkbox">
<label><input type="checkbox" id="walletSegwit" class="checkbox-inline" checked> Use a segwit address instead of a regular address. <span class="text-muted"><i>(recommended)</i></span></label></label> <label><input type="checkbox" id="walletSegwit" class="checkbox-inline" checked> Use a segwit address instead of a regular address. <span class="text-muted"><i>(recommended)</i></span></label></label> <br>
<label><input type="radio" id="walletSegwitp2sh" class="walletSegwitType" name="walletSegWitType" value="p2sh" checked> p2sh address</label> <br>
<label><input type="radio" id="walletSegwitBech32" class="walletSegwitType" name="walletSegWitType" value="bech32"> bech32 address</label>
</p> </p>
<label>Enable Replace by Fee (RBF)</label> <label>Enable Replace by Fee (RBF)</label>
@@ -188,6 +190,7 @@
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" id="walletToBtn">SegWit <span class="caret"></span></button> <button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" id="walletToBtn">SegWit <span class="caret"></span></button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="javascript:;" id="walletToSegWit">SegWit</a></li> <li><a href="javascript:;" id="walletToSegWit">SegWit</a></li>
<li><a href="javascript:;" id="walletToSegWitBech32">SegWit/Bech32</a></li>
<li><a href="javascript:;" id="walletToLegacy">Legacy</a></li> <li><a href="javascript:;" id="walletToLegacy">Legacy</a></li>
</ul> </ul>
</div> </div>
@@ -256,7 +259,7 @@
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-6">
<label><abbr title="the amount to pay in network miner fee">Transaction Fee</abbr>&nbsp;&nbsp;<a href="javascript:;" id="feesestwallet"><span class="glyphicon glyphicon-question-sign"></span></a></label> <label><abbr title="the amount to pay in network miner fee">Transaction Fee</abbr>&nbsp;&nbsp;<a href="javascript:;" id="feesestwallet"><span class="glyphicon glyphicon-question-sign"></span></a></label>
<input type="text" class="form-control" value="0.0004" id="txFee"> <input type="text" class="form-control" value="0.00004000" id="txFee">
</div> </div>
<div class="col-xs-5"> <div class="col-xs-5">
<label><abbr title="the amount to donate to coinb.in">Donation</abbr></label> <label><abbr title="the amount to donate to coinb.in">Donation</abbr></label>
@@ -335,7 +338,16 @@
</div> </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> <br>
</div> </div>
@@ -380,7 +392,17 @@
<input type="text" class="form-control hidden" id="brainwalletSegWit"> <input type="text" class="form-control hidden" id="brainwalletSegWit">
</div> </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> <br>
</div> </div>
@@ -560,12 +582,27 @@
</span> </span>
</div> </div>
<label>Seed (WIF)</label>
<div class="input-group">
<input id="newHDseed" type="text" class="form-control" value="" readonly>
<span class="input-group-btn">
<button class="deriveHDbtn btn btn-default" type="button"><span title="Derive from key" class="glyphicon glyphicon-chevron-right"></span></button>
</span>
</div>
<h3>Address Options</h3> <h3>Address Options</h3>
<p>You can use the advanced options below to generate different kinds of master addresses.</p> <p>You can use the advanced options below to generate different kinds of master addresses.</p>
<div class="checkbox"> <div class="checkbox">
<label><input type="checkbox" id="newHDBrainwallet" class="checkbox-inline"> Custom Seed or Brain Wallet</label> <label><input type="checkbox" id="newHDBrainwallet" class="checkbox-inline"> Custom Seed or Brain Wallet</label>
<input type="text" class="form-control hidden" id="HDBrainwallet"> <div class="hidden" id="HDBrainwalletInput">
<input type="text" class="form-control" id="HDBrainwallet">
<span class="text-muted">
Number of HMAC SHA-256 iterations for seed generation, higher value mean's also longer calculation
(use value 0 to calculate just SHA-256, like in previous coinb.in versions):
<input type="text" class="form-control" id="HDBrainwalletIters" value="50000" size="10">
</span>
</div>
</div> </div>
<input type="button" class="btn btn-primary" value="Generate" id="newHDKeysBtn"> <input type="button" class="btn btn-primary" value="Generate" id="newHDKeysBtn">
@@ -575,7 +612,7 @@
<h2>Transaction <small>Create a new transaction</small></h2> <h2>Transaction <small>Create a new transaction</small></h2>
<p>Use this page to create a raw transaction</p> <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"> <div class="input-group">
<span class="input-group-btn"> <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> <button class="btn btn-info qrcodeScanner" type="button" data-toggle="modal" data-target="#modalQrcodeScanner" forward-result="#redeemFrom"><span class="glyphicon glyphicon-camera"></span></button>
@@ -606,7 +643,7 @@
<label>Null Data</label> <span class="text-muted text-normal">(80 byte limit, <i>40 bytes recommended</i>)</span> <label>Null Data</label> <span class="text-muted text-normal">(80 byte limit, <i>40 bytes recommended</i>)</span>
<p class="checkbox"> <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> <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> </p>
@@ -621,7 +658,7 @@
<label>Replace By Fee (RBF)</label> <label>Replace By Fee (RBF)</label>
<p class="checkbox"> <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> </p>
<hr> <hr>
@@ -1169,23 +1206,40 @@
<p>The path of key derivation</p> <p>The path of key derivation</p>
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-6">
<b>Path</b><br> <b>Path</b><br>
<select class="form-control"> <select class="form-control" id="hdpathtype">
<option>Simple: m/i</option> <option value="simple">Simple: m/i</option>
<option value="custom">Custom</option>
</select> </select>
<div id="hdpath" class="hidden" style="margin-top:4px">
<span class="input-group">
<input type="text" class="form-control" value="m/0/1" title="WARNING: see #settings page when using hardened paths!"> <br>
<span class="input-group-addon"> / </span>
</span>
</div>
</div> </div>
<div class="col-md-2"> <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"> <input type="text" class="form-control derivation_index_start" value="0">
</div> </div>
<div class="col-md-2"> <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"> <input type="text" class="form-control derivation_index_end" value="1">
</div> </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> </div>
<hr> <hr>
@@ -1196,7 +1250,7 @@
<div class="derived_data"> <div class="derived_data">
<table class="table table-striped table-hover"> <table class="table table-striped table-hover">
<thead> <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> </thead>
<tbody> <tbody>
</tbody> </tbody>
@@ -1303,7 +1357,7 @@
<div class="tab-pane tab-content" id="about"> <div class="tab-pane tab-content" id="about">
<h2>About <small>open source bitcoin wallet</small></h2> <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>Compatible with bitcoin core</p>
<p>Github <a href="https://github.com/OutCast3k/coinbin/">https://github.com/OutCast3k/coinbin/</a></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> <p>TOR <a href="http://4zpinp6gdkjfplhk.onion">4zpinp6gdkjfplhk.onion</a></p>
@@ -1313,12 +1367,13 @@
<h3>Information</h3> <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 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 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> <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> <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> <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> <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> <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>
<div class="tab-pane tab-content" id="settings"> <div class="tab-pane tab-content" id="settings">
@@ -1331,7 +1386,8 @@
<p class="text-muted">Select which network you'd like to use for key pair generation.</p> <p class="text-muted">Select which network you'd like to use for key pair generation.</p>
<select class="form-control" id="coinjs_coin"> <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="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="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="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> <option value="bitcoin_testnet" rel="0x6f;0xef;0xc4;0x043587cf;0x04358394;false;false">Bitcoin (testnet)</option>
@@ -1388,8 +1444,14 @@
<p class="text-muted">Select the network you wish to broadcast the transaction via</p> <p class="text-muted">Select the network you wish to broadcast the transaction via</p>
<select class="form-control" id="coinjs_broadcast"> <select class="form-control" id="coinjs_broadcast">
<option value="coinb.in">coinb.in (Bitcoin mainnet)</option> <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_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="chain.so_dogecoin"> Chain.so (Dogecoin)</option>
<option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option> <option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option>
</select> </select>
@@ -1404,6 +1466,13 @@
<p class="text-muted">Select the network you wish to retreive your unspent inputs from</p> <p class="text-muted">Select the network you wish to retreive your unspent inputs from</p>
<select class="form-control" id="coinjs_utxo"> <select class="form-control" id="coinjs_utxo">
<option value="coinb.in">coinb.in (Bitcoin mainnet)</option> <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_litecoin"> Chain.so (Litecoin)</option>
<option value="chain.so_dogecoin"> Chain.so (Dogecoin)</option> <option value="chain.so_dogecoin"> Chain.so (Dogecoin)</option>
<option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option> <option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option>
@@ -1411,6 +1480,19 @@
</div> </div>
</div> </div>
<hr>
<div class="row">
<div class="col-md-12">
<b>HD wallet hardened path derivation</b>: <br>
<p class="text-muted">The path derivation for hardened paths was calculated wrong in earlier versions of coinb.in. Please select the old path derivation to recover HD wallet keys generated with older version of coinb.in.</p>
<select class="form-control" id="coinjs_derivation">
<option value="bip32_derivation">BIP32 compliant derivation</option>
<option value="coinbin_broken">Old (broken) coinb.in path derivation</option>
</select>
</div>
</div>
<br> <br>
<div id="statusSettings" class="hidden alert"> <div id="statusSettings" class="hidden alert">
@@ -1430,7 +1512,7 @@
<div id="footer"> <div id="footer">
<div class="container text-right"> <div class="container text-right">
<p class="text-muted">Version 1.4</p> <p class="text-muted">Version 1.6</p>
</div> </div>
</div> </div>
+177 -44
View File
@@ -18,11 +18,14 @@
coinjs.compressed = false; coinjs.compressed = false;
coinjs.hd_derivation = "bip32_derivation";
/* other vars */ /* other vars */
coinjs.developer = '3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN'; //bitcoin coinjs.developer = '33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G'; //bitcoin
/* bit(coinb.in) api vars */ /* 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.uid = '1';
coinjs.key = '12345678901234567890123456789012'; coinjs.key = '12345678901234567890123456789012';
@@ -155,7 +158,11 @@
} }
var s = coinjs.script(); 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(177);//OP_CHECKLOCKTIMEVERIFY
s.writeOp(117);//OP_DROP s.writeOp(117);//OP_DROP
s.writeBytes(Crypto.util.hexToBytes(pubkey)); s.writeBytes(Crypto.util.hexToBytes(pubkey));
@@ -198,7 +205,7 @@
var decode = coinjs.bech32_decode(address); var decode = coinjs.bech32_decode(address);
if(decode){ if(decode){
decode.data.shift(); 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; return r;
} }
@@ -302,7 +309,7 @@
return o; return o;
} else { } else {
return false; throw "Invalid checksum";
} }
} catch(e) { } catch(e) {
bech32rs = coinjs.bech32redeemscript(addr); bech32rs = coinjs.bech32redeemscript(addr);
@@ -603,6 +610,7 @@
r.parent_fingerprint = bytes.slice(5, 9); r.parent_fingerprint = bytes.slice(5, 9);
r.child_index = coinjs.uint(bytes.slice(9, 13), 4); r.child_index = coinjs.uint(bytes.slice(9, 13), 4);
r.chain_code = bytes.slice(13, 45); r.chain_code = bytes.slice(13, 45);
r.seed_wif = '';
r.key_bytes = bytes.slice(45, 78); r.key_bytes = bytes.slice(45, 78);
var c = coinjs.compressed; // get current default var c = coinjs.compressed; // get current default
@@ -613,10 +621,20 @@
var privkey = (r.key_bytes).slice(1, 33); var privkey = (r.key_bytes).slice(1, 33);
var privkeyHex = Crypto.util.bytesToHex(privkey); var privkeyHex = Crypto.util.bytesToHex(privkey);
var pubkey = coinjs.newPubkey(privkeyHex); 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, r.keys = {'privkey':privkeyHex,
'pubkey':pubkey, 'pubkey':pubkey,
'address':coinjs.pubkey2address(pubkey), 'address':address.address,
'script':address.redeemscript,
'wif':coinjs.privkey2wif(privkeyHex)}; 'wif':coinjs.privkey2wif(privkeyHex)};
} else if(r.key_bytes[0] == 0x02 || r.key_bytes[0] == 0x03) { } else if(r.key_bytes[0] == 0x02 || r.key_bytes[0] == 0x03) {
@@ -633,6 +651,8 @@
coinjs.compressed = c; // reset to default coinjs.compressed = c; // reset to default
} }
return r;
} }
// extend prv/pub key // extend prv/pub key
@@ -646,10 +666,43 @@
'pubkey':this.keys.pubkey}); '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 // derive key from index
r.derive = function(i){ r.derive = function(i){
i = (i)?i:0; i = (i)?i:0;
var blob = (Crypto.util.hexToBytes(this.keys.pubkey)).concat(coinjs.numToBytes(i,4).reverse()); if ((i >= 0x80000000) && (coinjs.hd_derivation == "bip32_derivation")) {
var blob = (Crypto.util.hexToBytes("00").concat(Crypto.util.hexToBytes(this.keys.privkey)).concat(coinjs.numToBytes(i,4).reverse()));
} else {
var blob = (Crypto.util.hexToBytes(this.keys.pubkey)).concat(coinjs.numToBytes(i,4).reverse());
}
var j = new jsSHA(Crypto.util.bytesToHex(blob), 'HEX'); var j = new jsSHA(Crypto.util.bytesToHex(blob), 'HEX');
var hash = j.getHMAC(Crypto.util.bytesToHex(r.chain_code), "HEX", "SHA-512", "HEX"); var hash = j.getHMAC(Crypto.util.bytesToHex(r.chain_code), "HEX", "SHA-512", "HEX");
@@ -660,23 +713,34 @@
var ecparams = EllipticCurve.getSECCurveByName("secp256k1"); var ecparams = EllipticCurve.getSECCurveByName("secp256k1");
var curve = ecparams.getCurve(); var curve = ecparams.getCurve();
var k, key, pubkey, o; var k, key, pubkey, o, addr_format, address_fun, address;
o = coinjs.clone(this); o = coinjs.clone(this);
o.chain_code = ir; o.chain_code = ir;
o.child_index = i; 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'){ if(this.type=='private'){
// derive key pair from from a xprv key // derive key pair from from a xprv key
k = il.add(new BigInteger([0].concat(Crypto.util.hexToBytes(this.keys.privkey)))).mod(ecparams.getN()); k = il.add(new BigInteger([0].concat(Crypto.util.hexToBytes(this.keys.privkey)))).mod(ecparams.getN());
key = Crypto.util.bytesToHex(k.toByteArrayUnsigned()); key = Crypto.util.bytesToHex(k.toByteArrayUnsigned());
pubkey = coinjs.newPubkey(key); pubkey = coinjs.newPubkey(key);
address = address_fun(pubkey);
o.keys = {'privkey':key, o.keys = {'privkey':key,
'pubkey':pubkey, 'pubkey':pubkey,
'wif':coinjs.privkey2wif(key), 'wif':coinjs.privkey2wif(key),
'address':coinjs.pubkey2address(pubkey)}; 'address':address.address,
'script':address.redeemscript};
} else if (this.type=='public'){ } else if (this.type=='public'){
// derive xpub key from an xpub key // derive xpub key from an xpub key
@@ -693,22 +757,38 @@
publicKeyBytesCompressed.unshift(0x03) publicKeyBytesCompressed.unshift(0x03)
} }
pubkey = Crypto.util.bytesToHex(publicKeyBytesCompressed); pubkey = Crypto.util.bytesToHex(publicKeyBytesCompressed);
address = address_fun(pubkey);
o.keys = {'pubkey':pubkey, o.keys = {'pubkey':pubkey,
'address':coinjs.pubkey2address(pubkey)} 'address':address.address,
'script':address.redeemscript}
} else { } else {
// fail // fail
} }
o.parent_fingerprint = (ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(r.keys.pubkey),{asBytes:true}),{asBytes:true})).slice(0,4); o.parent_fingerprint = (ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(r.keys.pubkey),{asBytes:true}),{asBytes:true})).slice(0,4);
o.keys_extended = o.extend(); o.keys_extended = o.extend();
return o; return o;
} }
// make a master hd xprv/xpub // make a master hd xprv/xpub
r.master = function(pass) { r.master = function(pass, iters) {
var seed = (pass) ? Crypto.SHA256(pass) : coinjs.newPrivkey(); if (pass) {
var seed_iters = (iters) ? Math.abs(iters * 1) : 0;
if (seed_iters == 0) {
var seed = Crypto.SHA256(pass);
} else {
var seed = Crypto.util.hexToBytes("0000000000000000000000000000000000000000000000000000000000000000");
for (var i = 0; i < seed_iters; i++) {
seed = Crypto.HMAC(Crypto.SHA256, seed, pass, { asBytes: true });
}
seed = Crypto.util.bytesToHex(seed);
}
} else {
var seed = coinjs.newPrivkey();
}
var seed_wif = coinjs.privkey2wif(seed);
var hasher = new jsSHA(seed, 'HEX'); var hasher = new jsSHA(seed, 'HEX');
var I = hasher.getHMAC("Bitcoin seed", "TEXT", "SHA-512", "HEX"); var I = hasher.getHMAC("Bitcoin seed", "TEXT", "SHA-512", "HEX");
@@ -720,6 +800,7 @@
'parent_fingerprint':[0,0,0,0], 'parent_fingerprint':[0,0,0,0],
'child_index':0, 'child_index':0,
'chain_code':chain, 'chain_code':chain,
'seed_wif':seed_wif,
'privkey':I.slice(0, 64), 'privkey':I.slice(0, 64),
'pubkey':coinjs.newPubkey(I.slice(0, 64))}); 'pubkey':coinjs.newPubkey(I.slice(0, 64))});
} }
@@ -764,11 +845,12 @@
var ret = pub.concat(checksum); var ret = pub.concat(checksum);
o.pubkey = coinjs.base58encode(ret); o.pubkey = coinjs.base58encode(ret);
} }
o.seed_wif = data.seed_wif;
return o; return o;
} }
r.parse(); return r.parse();
return r;
} }
@@ -846,6 +928,9 @@
var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired); var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired);
r.address = multi['address']; r.address = multi['address'];
r.type = 'multisig__'; // using __ for now to differentiat from the other object .type == "multisig" 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 } else if((s.chunks.length==2) && (s.buffer[0] == 0 && s.buffer[1] == 20)){ // SEGWIT
r = {}; r = {};
r.type = "segwit__"; r.type = "segwit__";
@@ -859,6 +944,8 @@
r.pubkey = Crypto.util.bytesToHex(s.chunks[3]); r.pubkey = Crypto.util.bytesToHex(s.chunks[3]);
r.checklocktimeverify = coinjs.bytesToNum(s.chunks[0].slice()); r.checklocktimeverify = coinjs.bytesToNum(s.chunks[0].slice());
r.address = coinjs.simpleHodlAddress(r.pubkey, r.checklocktimeverify).address; r.address = coinjs.simpleHodlAddress(r.pubkey, r.checklocktimeverify).address;
var rs = Crypto.util.bytesToHex(s.buffer);
r.redeemscript = rs;
r.type = "hodl__"; r.type = "hodl__";
} }
} catch(e) { } catch(e) {
@@ -1028,12 +1115,16 @@
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=unspent&address='+address+'&r='+Math.random(), callback, "GET"); 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 */ /* add unspent to transaction */
r.addUnspent = function(address, callback, script, segwit, sequence){ r.addUnspent = function(address, callback, script, segwit, sequence){
var self = this; var self = this;
this.listUnspent(address, function(data){ this.listUnspent(address, function(data){
var s = coinjs.script(); var s = coinjs.script();
var pubkeyScript = s.pubkeyHash(address);
var value = 0; var value = 0;
var total = 0; var total = 0;
var x = {}; var x = {};
@@ -1049,32 +1140,37 @@
var unspent = xmlDoc.getElementsByTagName("unspent")[0]; var unspent = xmlDoc.getElementsByTagName("unspent")[0];
for(i=1;i<=unspent.childElementCount;i++){ if(unspent){
var u = xmlDoc.getElementsByTagName("unspent_"+i)[0] for(i=1;i<=unspent.childElementCount;i++){
var txhash = (u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue).match(/.{1,2}/g).reverse().join("")+''; var u = xmlDoc.getElementsByTagName("unspent_"+i)[0]
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue; var txhash = (u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue).match(/.{1,2}/g).reverse().join("")+'';
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue; var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
if(segwit){ if(segwit){
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother. /* 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. */ It is not standard and removed during the signing procedure. */
s = coinjs.script(); s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(script)); s.writeBytes(Crypto.util.hexToBytes(script));
s.writeOp(0); s.writeOp(0);
s.writeBytes(coinjs.numToBytes(u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1, 8)); s.writeBytes(coinjs.numToBytes(u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1, 8));
scr = Crypto.util.bytesToHex(s.buffer); 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.value = value;
x.total = total; x.total = total;
x.response = xmlDoc.getElementsByTagName("response")[0].childNodes[0].nodeValue;
return callback(x); return callback(x);
}); });
} }
@@ -1298,7 +1394,14 @@
return {'type':'segwit', 'signed':signed, 'signatures': sigs, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[0]), 'value': value}; 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 } 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 // 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 } 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! // multisig script, without signature!
return {'type':'multisig', 'signed':'false', 'signatures':0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)}; return {'type':'multisig', 'signed':'false', 'signatures':0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
@@ -1550,10 +1653,20 @@
if(!witness_used.includes(y)){ if(!witness_used.includes(y)){
var sw = coinjs.segwitAddress(this.witness[y][1]); var sw = coinjs.segwitAddress(this.witness[y][1]);
var b32 = coinjs.bech32Address(this.witness[y][1]); var b32 = coinjs.bech32Address(this.witness[y][1]);
if((sw['redeemscript'] == Crypto.util.bytesToHex(this.ins[i].script.chunks[0])) || (b32['redeemscript'] == Crypto.util.bytesToHex(this.ins[i].script.chunks[0]))){ var rs = '';
if(this.ins[i].script.chunks.length>=1){
rs = Crypto.util.bytesToHex(this.ins[i].script.chunks[0]);
} else if (this.ins[i].script.chunks.length==0){
rs = b32['redeemscript'];
}
if((sw['redeemscript'] == rs) || (b32['redeemscript'] == rs)){
witness_order.push(this.witness[y]); witness_order.push(this.witness[y]);
witness_used.push(y); witness_used.push(y);
if(b32['redeemscript'] == Crypto.util.bytesToHex(this.ins[i].script.chunks[0])){
// bech32, empty redeemscript
if(b32['redeemscript'] == rs){
this.ins[index].script = coinjs.script(); this.ins[index].script = coinjs.script();
} }
break; break;
@@ -1561,6 +1674,7 @@
} }
} }
} }
this.witness = witness_order; this.witness = witness_order;
} }
} }
@@ -1908,12 +2022,31 @@
} }
} }
coinjs.numToByteArray = function(num) { function scriptNumSize(i) {
if (num <= 256) { return i > 0x7fffffff ? 5
return [num]; : i > 0x7fffff ? 4
} else { : i > 0x7fff ? 3
return [num % 256].concat(coinjs.numToByteArray(Math.floor(num / 256))); : 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) { coinjs.numToVarInt = function(num) {
+323 -99
View File
@@ -37,11 +37,17 @@ $(document).ready(function() {
$("#walletKeys .walletSegWitRS").addClass("hidden"); $("#walletKeys .walletSegWitRS").addClass("hidden");
if($("#walletSegwit").is(":checked")){ if($("#walletSegwit").is(":checked")){
var sw = coinjs.segwitAddress(pubkey); if($("#walletSegwitBech32").is(":checked")){
address = sw.address; var sw = coinjs.bech32Address(pubkey);
address = sw.address;
} else {
var sw = coinjs.segwitAddress(pubkey);
address = sw.address;
}
$("#walletKeys .walletSegWitRS").removeClass("hidden"); $("#walletKeys .walletSegWitRS").removeClass("hidden");
$("#walletKeys .walletSegWitRS input:text").val(sw.redeemscript); $("#walletKeys .walletSegWitRS input:text").val(sw.redeemscript);
} }
$("#walletAddress").html(address); $("#walletAddress").html(address);
@@ -59,7 +65,6 @@ $(document).ready(function() {
$("#openWallet").removeClass("hidden").show(); $("#openWallet").removeClass("hidden").show();
walletBalance(); walletBalance();
checkBalanceLoop();
} else { } else {
$("#openLoginStatus").html("Your passwords do not match!").removeClass("hidden").fadeOut().fadeIn(); $("#openLoginStatus").html("Your passwords do not match!").removeClass("hidden").fadeOut().fadeIn();
} }
@@ -94,9 +99,25 @@ $(document).ready(function() {
$("#openLoginStatus").html("").hide(); $("#openLoginStatus").html("").hide();
}); });
$("#walletSegwit").click(function(){
if($(this).is(":checked")){
$(".walletSegwitType").attr('disabled',false);
} else {
$(".walletSegwitType").attr('disabled',true);
}
});
$("#walletToSegWit").click(function(){ $("#walletToSegWit").click(function(){
$("#walletToBtn").html('SegWit <span class="caret"></span>'); $("#walletToBtn").html('SegWit <span class="caret"></span>');
$("#walletSegwit")[0].checked = true; $("#walletSegwit")[0].checked = true;
$("#walletSegwitp2sh")[0].checked = true;
$("#openBtn").click();
});
$("#walletToSegWitBech32").click(function(){
$("#walletToBtn").html('Bech32 <span class="caret"></span>');
$("#walletSegwit")[0].checked = true;
$("#walletSegwitBech32")[0].checked = true;
$("#openBtn").click(); $("#openBtn").click();
}); });
@@ -106,13 +127,12 @@ $(document).ready(function() {
$("#openBtn").click(); $("#openBtn").click();
}); });
$("#walletShowKeys").click(function(){ $("#walletShowKeys").click(function(){
$("#walletKeys").removeClass("hidden"); $("#walletKeys").removeClass("hidden");
$("#walletSpend").removeClass("hidden").addClass("hidden"); $("#walletSpend").removeClass("hidden").addClass("hidden");
}); });
$("#walletBalance").click(function(){ $("#walletBalance, #walletAddress, #walletQrCode").click(function(){
walletBalance(); walletBalance();
}); });
@@ -142,11 +162,15 @@ $(document).ready(function() {
var script = false; var script = false;
if($("#walletSegwit").is(":checked")){ if($("#walletSegwit").is(":checked")){
var sw = coinjs.segwitAddress($("#walletKeys .pubkey").val()); if($("#walletSegwitBech32").is(":checked")){
var sw = coinjs.bech32Address($("#walletKeys .pubkey").val());
} else {
var sw = coinjs.segwitAddress($("#walletKeys .pubkey").val());
}
script = sw.redeemscript; script = sw.redeemscript;
} }
var sequence = false; var sequence = 0xffffffff-1;
if($("#walletRBF").is(":checked")){ if($("#walletRBF").is(":checked")){
sequence = 0xffffffff-2; sequence = 0xffffffff-2;
} }
@@ -272,28 +296,20 @@ $(document).ready(function() {
}); });
function walletBalance(){ function walletBalance(){
var tx = coinjs.transaction(); if($("#walletLoader").hasClass("hidden")){
$("#walletLoader").removeClass("hidden"); var tx = coinjs.transaction();
coinjs.addressBalance($("#walletAddress").html(),function(data){ $("#walletLoader").removeClass("hidden");
if($(data).find("result").text()==1){ coinjs.addressBalance($("#walletAddress").html(),function(data){
var v = $(data).find("balance").text()/100000000; if($(data).find("result").text()==1){
$("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn(); var v = $(data).find("balance").text()/100000000;
} else { $("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn();
} else {
$("#walletBalance").html("0.00 BTC").attr('rel',v).fadeOut().fadeIn(); $("#walletBalance").html("0.00 BTC").attr('rel',v).fadeOut().fadeIn();
} }
$("#walletLoader").addClass("hidden"); $("#walletLoader").addClass("hidden");
}); });
} }
function checkBalanceLoop(){
clearTimeout(wallet_timer);
wallet_timer = setTimeout(function(){
if($("#walletLoader").hasClass("hidden")){
walletBalance();
}
checkBalanceLoop();
},45000);
} }
/* new -> address code */ /* new -> address code */
@@ -319,7 +335,22 @@ $(document).ready(function() {
$("#aes256passStatus").removeClass("hidden"); $("#aes256passStatus").removeClass("hidden");
} }
$("#newPrivKeyEnc").val(CryptoJS.AES.encrypt(coin.wif, $("#aes256pass").val())+''); $("#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(){ $("#newBrainwallet").click(function(){
@@ -367,6 +398,22 @@ $(document).ready(function() {
coinjs.compressed = compressed; 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 */ /* new -> multisig code */
@@ -523,18 +570,20 @@ $(document).ready(function() {
$("#newHDKeysBtn").click(function(){ $("#newHDKeysBtn").click(function(){
coinjs.compressed = true; coinjs.compressed = true;
var s = ($("#newHDBrainwallet").is(":checked")) ? $("#HDBrainwallet").val() : null; var s = ($("#newHDBrainwallet").is(":checked")) ? $("#HDBrainwallet").val() : null;
var siters = ($("#newHDBrainwallet").is(":checked")) ? $("#HDBrainwalletIters").val()*1 : null;
var hd = coinjs.hd(); var hd = coinjs.hd();
var pair = hd.master(s); var pair = hd.master(s, siters);
$("#newHDxpub").val(pair.pubkey); $("#newHDxpub").val(pair.pubkey);
$("#newHDxprv").val(pair.privkey); $("#newHDxprv").val(pair.privkey);
$("#newHDseed").val(pair.seed_wif);
}); });
$("#newHDBrainwallet").click(function(){ $("#newHDBrainwallet").click(function(){
if($(this).is(":checked")){ if($(this).is(":checked")){
$("#HDBrainwallet").removeClass("hidden"); $("#HDBrainwalletInput").removeClass("hidden");
} else { } else {
$("#HDBrainwallet").addClass("hidden"); $("#HDBrainwalletInput").addClass("hidden");
} }
}); });
@@ -600,7 +649,7 @@ $(document).ready(function() {
} }
if(!$(o).hasClass("has-error")){ if(!$(o).hasClass("has-error")){
var seq = null; var seq = 0xffffffff-1;
if($("#txRBF").is(":checked")){ if($("#txRBF").is(":checked")){
seq = 0xffffffff-2; seq = 0xffffffff-2;
} }
@@ -699,24 +748,24 @@ $(document).ready(function() {
$.each($("#walletSpendTo .output"), function(i,o){ $.each($("#walletSpendTo .output"), function(i,o){
var addr = $('.addressTo',o); var addr = $('.addressTo',o);
var ad = coinjs.addressDecode(addr.val()); var ad = coinjs.addressDecode(addr.val());
if (ad.version == coinjs.multisig){ // p2sh if (ad.version == coinjs.pub){ // p2pkh
$("#fees .txo_p2sh").val(($("#fees .txo_p2sh").val()*1)+1);
$("#fees .txo_p2sh").trigger('input');
} else { // p2pkh
$("#fees .txo_p2pkh").val(($("#fees .txo_p2pkh").val()*1)+1); $("#fees .txo_p2pkh").val(($("#fees .txo_p2pkh").val()*1)+1);
$("#fees .txo_p2pkh").trigger('input'); $("#fees .txo_p2pkh").trigger('input');
} else { // p2psh
$("#fees .txo_p2sh").val(($("#fees .txo_p2sh").val()*1)+1);
$("#fees .txo_p2sh").trigger('input');
} }
}); });
if(($("#developerDonation").val()*1)>0){ if(($("#developerDonation").val()*1)>0){
var addr = coinjs.developer; var addr = coinjs.developer;
var ad = coinjs.addressDecode(addr); var ad = coinjs.addressDecode(addr);
if (ad.version == coinjs.multisig){ // p2sh if (ad.version == coinjs.pub){ // p2pkh
$("#fees .txo_p2pkh").val(($("#fees .txo_p2pkh").val()*1)+1);
$("#fees .txo_p2pkh").trigger('input');
} else { // p2psh
$("#fees .txo_p2sh").val(($("#fees .txo_p2sh").val()*1)+1); $("#fees .txo_p2sh").val(($("#fees .txo_p2sh").val()*1)+1);
$("#fees .txo_p2sh").trigger('input'); $("#fees .txo_p2sh").trigger('input');
} else { // p2pkh
$("#fees .txo_p2pkh").val(($("#fees .txo_p2pkh").val()*1)+1);
$("#fees .txo_p2pkh").trigger('input');
} }
} }
@@ -829,12 +878,12 @@ $(document).ready(function() {
/* redeem from button code */ /* redeem from button code */
$("#redeemFromBtn").click(function(){ $("#redeemFromBtn").click(function(){
var redeem = redeemingFrom($("#redeemFrom").val()); var redeem = redeemingFrom($("#redeemFrom").val());
$("#redeemFromStatus, #redeemFromAddress").addClass('hidden'); $("#redeemFromStatus, #redeemFromAddress").addClass('hidden');
if(redeem.from=='multisigAddress'){ 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; return false;
} }
@@ -851,11 +900,32 @@ $(document).ready(function() {
var host = $(this).attr('rel'); 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'){ if(host=='chain.so_bitcoinmainnet'){
listUnspentChainso_Litecoin(redeem); listUnspentChainso(redeem, "BTC");
} else if(host=='chain.so_litecoin'){
listUnspentChainso(redeem, "LTC");
} else if(host=='chain.so_dogecoin'){ } 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'){ } else if(host=='cryptoid.info_carboncoin'){
listUnspentCryptoidinfo_Carboncoin(redeem); listUnspentCryptoidinfo_Carboncoin(redeem);
} else { } else {
@@ -864,8 +934,8 @@ $(document).ready(function() {
if($("#redeemFromStatus").hasClass("hidden")) { if($("#redeemFromStatus").hasClass("hidden")) {
// An ethical dilemma: Should we automatically set nLockTime? // An ethical dilemma: Should we automatically set nLockTime?
if(redeem.from == 'redeemScript' && redeem.decodedRs.type == "hodl__") { if(redeem.from == 'redeemScript' && redeem.type == "hodl__") {
$("#nLockTime").val(redeem.decodedRs.checklocktimeverify); $("#nLockTime").val(redeem.decodescript.checklocktimeverify);
} else { } else {
$("#nLockTime").val(0); $("#nLockTime").val(0);
} }
@@ -901,11 +971,19 @@ $(document).ready(function() {
r.addr = decodeRs['address']; r.addr = decodeRs['address'];
r.from = 'redeemScript'; r.from = 'redeemScript';
r.decodedRs = decodeRs.redeemscript; r.decodedRs = decodeRs.redeemscript;
r.type = decodeRs['type'];
r.redeemscript = true; r.redeemscript = true;
r.decodescript = decodeRs;
} else { // something else } else { // something else
r.addr = ''; if(string.match(/^[a-f0-9]{64}$/i)){
r.from = 'other'; r.addr = string;
r.redeemscript = false; r.from = 'txid';
r.redeemscript = false;
} else {
r.addr = '';
r.from = 'other';
r.redeemscript = false;
}
} }
} }
return r; return r;
@@ -972,9 +1050,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*/ /* default function to retreive unspent outputs*/
function listUnspentDefault(redeem){ function listUnspentDefault(redeem){
var tx = coinjs.transaction(); 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){ tx.listUnspent(redeem.addr, function(data){
if(redeem.addr) { 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>'); $("#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>');
@@ -997,25 +1125,27 @@ $(document).ready(function() {
} }
/* retrieve unspent data from chainso for litecoin */ /* retrieve unspent data from blockcypher */
function listUnspentChainso_Litecoin(redeem){ function listUnspentBlockcypher(redeem,network){
$.ajax ({ $.ajax ({
type: "GET", 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", dataType: "json",
error: function(data) { error: function(data) {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!'); $("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
}, },
success: function(data) { 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>'); $("#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){ for(var i in data.txrefs){
var o = data.data.txs[i]; var o = data.txrefs[i];
var tx = ((o.txid).match(/.{1,2}/g).reverse()).join("")+''; var tx = ((""+o.tx_hash).match(/.{1,2}/g).reverse()).join("")+'';
var n = o.output_no; if(tx.match(/^[a-f0-9]+$/)){
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o.script_hex; var n = o.tx_output_n;
var amount = o.value; var script = (redeem.redeemscript==true) ? redeem.decodedRs : o.script;
addOutput(tx, n, script, amount); var amount = ((o.value.toString()*1)/100000000).toFixed(8);
addOutput(tx, n, script, amount);
}
} }
} else { } else {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.'); $("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.');
@@ -1062,19 +1192,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 ({ $.ajax ({
type: "GET", 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", dataType: "json",
error: function(data) { error: function(data) {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!'); $("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
}, },
success: function(data) { success: function(data) {
if((data.status && data.data) && data.status=='success'){ if((data.status && data.data) && data.status=='success'){
$("#redeemFromAddress").removeClass('hidden').html( $("#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>');
'<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){ for(var i in data.data.txs){
var o = data.data.txs[i]; var o = data.data.txs[i];
var tx = ((""+o.txid).match(/.{1,2}/g).reverse()).join("")+''; var tx = ((""+o.txid).match(/.{1,2}/g).reverse()).join("")+'';
@@ -1096,6 +1261,7 @@ $(document).ready(function() {
}); });
} }
/* math to calculate the inputs and outputs */ /* math to calculate the inputs and outputs */
function totalInputAmount(){ function totalInputAmount(){
@@ -1155,7 +1321,7 @@ $(document).ready(function() {
rawSubmitDefault(this); rawSubmitDefault(this);
}); });
// broadcast transaction vai coinbin (default) // broadcast transaction via coinbin (default)
function rawSubmitDefault(btn){ function rawSubmitDefault(btn){
var thisbtn = btn; var thisbtn = btn;
$(thisbtn).val('Please wait, loading...').attr('disabled',true); $(thisbtn).val('Please wait, loading...').attr('disabled',true);
@@ -1170,8 +1336,7 @@ $(document).ready(function() {
success: function(data) { success: function(data) {
$("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden'); $("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden');
if($(data).find("result").text()==1){ if($(data).find("result").text()==1){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger'); $("#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>');
$("#rawTransactionStatus").html('txid: '+$(data).find("txid").text());
} else { } else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> '); $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
} }
@@ -1197,8 +1362,7 @@ $(document).ready(function() {
success: function(data) { success: function(data) {
$("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden'); $("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden');
if($(data).find("result").text()==1){ if($(data).find("result").text()==1){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger'); $("#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>');
$("#rawTransactionStatus").html('txid: '+$(data).find("txid").text());
} else { } else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> '); $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
} }
@@ -1211,11 +1375,11 @@ $(document).ready(function() {
} }
// broadcast transaction via chain.so (mainnet) // broadcast transaction via chain.so (mainnet)
function rawSubmitChainso_BitcoinMainnet(thisbtn){ function rawSubmitChainso(thisbtn, network){
$(thisbtn).val('Please wait, loading...').attr('disabled',true); $(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({ $.ajax ({
type: "POST", 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()}, data: {"tx_hex":$("#rawTransaction").val()},
dataType: "json", dataType: "json",
error: function(data) { error: function(data) {
@@ -1227,7 +1391,7 @@ $(document).ready(function() {
}, },
success: function(data) { success: function(data) {
if(data.status && data.data.txid){ 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 { } else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>'); $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
} }
@@ -1240,22 +1404,20 @@ $(document).ready(function() {
} }
// broadcast transaction via blockcypher.com (mainnet) // broadcast transaction via blockcypher.com (mainnet)
function rawSubmitblockcypher_BitcoinMainnet(thisbtn){ function rawSubmitblockcypher(thisbtn, network){
$(thisbtn).val('Please wait, loading...').attr('disabled',true); $(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({ $.ajax ({
type: "POST", 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()}), data: JSON.stringify({"tx":$("#rawTransaction").val()}),
error: function(data) { error: function(data) {
var obj = $.parseJSON(data.responseText); var r = 'Failed to broadcast: error code=' + data.status.toString() + ' ' + data.statusText;
var r = ' ';
r += (obj.error) ? obj.error : '';
r = (r!='') ? r : ' Failed to broadcast'; // build response
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>'); $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}, },
success: function(data) { success: function(data) {
if((data.tx) && data.tx.hash){ 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 { } else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>'); $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
} }
@@ -1267,27 +1429,24 @@ $(document).ready(function() {
}); });
} }
// broadcast transaction via blockchair
// broadcast transaction via chain.so for dogecoin function rawSubmitblockchair(thisbtn, network){
function rawSubmitchainso_dogecoin(thisbtn){
$(thisbtn).val('Please wait, loading...').attr('disabled',true); $(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({ $.ajax ({
type: "POST", type: "POST",
url: "https://chain.so/api/v2/send_tx/DOGE", url: "https://api.blockchair.com/"+network+"/push/transaction",
data: {"tx_hex":$("#rawTransaction").val()}, data: {"data":$("#rawTransaction").val()},
dataType: "json", dataType: "json",
error: function(data) { error: function(data) {
var obj = $.parseJSON(data.responseText); var r = 'Failed to broadcast: error code=' + data.status.toString() + ' ' + data.statusText;
var r = ' ';
r += (obj.data.tx_hex) ? ' '+obj.data.tx_hex : '';
r = (r!='') ? r : ' Failed to broadcast'; // build response
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>'); $("#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)); // console.error(JSON.stringify(data, null, 4));
}, },
success: function(data) { success: function(data) {
// console.info(JSON.stringify(data, null, 4)); // console.info(JSON.stringify(data, null, 4));
if((data.status && data.data) && data.status=='success'){ if((data.context && data.data) && data.context.code=='200'){
$("#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.transaction_hash + '<br> <a href="https://blockchair.com/'+network+'/transaction/' + data.data.transaction_hash + '" target="_blank">View on Blockchain Explorer</a>');
} else { } else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>'); $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
} }
@@ -1524,6 +1683,7 @@ $(document).ready(function() {
if(hex == hex_cmp_prv || hex == hex_cmp_pub){ if(hex == hex_cmp_prv || hex == hex_cmp_pub){
var hd = coinjs.hd(s); var hd = coinjs.hd(s);
$("#verifyHDaddress .hdKey").html(s); $("#verifyHDaddress .hdKey").html(s);
$("#verifyHDaddress .seed_wif").val(hd.seed_wif);
$("#verifyHDaddress .chain_code").val(Crypto.util.bytesToHex(hd.chain_code)); $("#verifyHDaddress .chain_code").val(Crypto.util.bytesToHex(hd.chain_code));
$("#verifyHDaddress .depth").val(hd.depth); $("#verifyHDaddress .depth").val(hd.depth);
$("#verifyHDaddress .version").val('0x'+(hd.version).toString(16)); $("#verifyHDaddress .version").val('0x'+(hd.version).toString(16));
@@ -1544,15 +1704,29 @@ $(document).ready(function() {
function deriveHDaddress() { function deriveHDaddress() {
var hd = coinjs.hd($("#verifyHDaddress .hdKey").html()); var hd = coinjs.hd($("#verifyHDaddress .hdKey").html());
var index_start = $("#verifyHDaddress .derivation_index_start").val()*1; var index_start = $("#verifyHDaddress .derivation_index_start").val();
var index_end = $("#verifyHDaddress .derivation_index_end").val()*1; if ((index_start.length > 1) && (index_start[index_start.length - 1] == '\'')) {
var use_private_index = '\'';
index_start = index_start.replace(/[']/, "") * 1;
} else {
var use_private_index = '';
index_start = index_start.replace(/[']/, "") * 1;
}
var index_end = $("#verifyHDaddress .derivation_index_end").val().replace(/[']/, "") * 1;
$("#verifyHDaddress .derivation_index_end").val(index_end + use_private_index);
var html = ''; var html = '';
$("#verifyHDaddress .derived_data table tbody").html(""); $("#verifyHDaddress .derived_data table tbody").html("");
for(var i=index_start;i<=index_end;i++){ 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+use_private_index);
$("#hdpath").removeClass(); // make it visible
}
html += '<tr>'; html += '<tr>';
html += '<td>'+i+'</td>'; 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.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.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.pubkey+'" readonly></td>';
html += '<td><input type="text" class="form-control" value="'+((derived.keys_extended.privkey)?derived.keys_extended.privkey:'')+'" readonly></td>'; html += '<td><input type="text" class="form-control" value="'+((derived.keys_extended.privkey)?derived.keys_extended.privkey:'')+'" readonly></td>';
@@ -1562,6 +1736,15 @@ $(document).ready(function() {
} }
$("#hdpathtype").change(function(){
if($(this).val()=='simple'){
$("#hdpath").removeClass().addClass("hidden");
} else {
$("#hdpath").removeClass();
}
});
/* sign code */ /* sign code */
$("#signBtn").click(function(){ $("#signBtn").click(function(){
@@ -1692,7 +1875,7 @@ $(document).ready(function() {
$('a[data-toggle="tab"]').on('click', function(e) { $('a[data-toggle="tab"]').on('click', function(e) {
e.preventDefault(); e.preventDefault();
if(e.target){ if(e.target && $(e.target).attr('href')) {
history.pushState(null, null, '#'+$(e.target).attr('href').substr(1)); history.pushState(null, null, '#'+$(e.target).attr('href').substr(1));
} }
}); });
@@ -1744,9 +1927,19 @@ $(document).ready(function() {
coinjs.hdkey.pub = $("#coinjs_hdpub").val()*1; coinjs.hdkey.pub = $("#coinjs_hdpub").val()*1;
coinjs.hdkey.prv = $("#coinjs_hdprv").val()*1; coinjs.hdkey.prv = $("#coinjs_hdprv").val()*1;
coinjs.hd_derivation = $("#coinjs_derivation").val();
configureBroadcast(); configureBroadcast();
configureGetUnspentTx(); 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(); $("#statusSettings").addClass("alert-success").removeClass("hidden").html("<span class=\"glyphicon glyphicon-ok\"></span> Settings updates successfully").fadeOut().fadeIn();
} else { } else {
$("#statusSettings").addClass("alert-danger").removeClass("hidden").html("There is an error with one or more of your settings"); $("#statusSettings").addClass("alert-danger").removeClass("hidden").html("There is an error with one or more of your settings");
@@ -1781,6 +1974,7 @@ $(document).ready(function() {
$("#coinjs_multisig").val(o[2]); $("#coinjs_multisig").val(o[2]);
$("#coinjs_hdpub").val(o[3]); $("#coinjs_hdpub").val(o[3]);
$("#coinjs_hdprv").val(o[4]); $("#coinjs_hdprv").val(o[4]);
$("#coinjs_derivation").val(o[7]);
// hide/show custom screen // hide/show custom screen
if($("option:selected",this).val()=="custom"){ if($("option:selected",this).val()=="custom"){
@@ -1792,18 +1986,48 @@ $(document).ready(function() {
function configureBroadcast(){ function configureBroadcast(){
var host = $("#coinjs_broadcast option:selected").val(); 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(""); $("#rawSubmitBtn").unbind("");
if(host=="chain.so_bitcoinmainnet"){ if(host=="chain.so_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){ $("#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"){ } else if(host=="chain.so_dogecoin"){
$("#rawSubmitBtn").click(function(){ $("#rawSubmitBtn").click(function(){
rawSubmitchainso_dogecoin(this); rawSubmitchainso(this, "DOGE");
}); });
} else if(host=="blockcypher_bitcoinmainnet"){ } else if(host=="blockcypher_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){ $("#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"){ } else if(host=="cryptoid.info_carboncoin"){
$("#rawSubmitBtn").click(function(){ $("#rawSubmitBtn").click(function(){
+6 -5
View File
@@ -1,9 +1,9 @@
---- Version 1.4 2018.05.27 --- ---- Version 1.6 2020.10.02 ----
77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js 77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js
3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js 3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js
253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js 253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js
dda26795fcd22541612067d44cf72ecae62f092b ./js/coinbin.js cb5717166bf1c99abbd75a06013067c4a5897d5a ./js/coinbin.js
eec3c5f1c5f69a34205613f6bf62ff9cc5a8d07a ./js/coin.js 911fb7bdba24269029f27659e4040cd991b2307c ./js/coin.js
988565bc2cb402d63ed5c5fd7ff47c4278efc2c5 ./js/collapse.js 988565bc2cb402d63ed5c5fd7ff47c4278efc2c5 ./js/collapse.js
9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js 9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js
f7c09f2f5a721371e7d478050119f7e2d58e3ef9 ./js/crypto-sha256-hmac.js f7c09f2f5a721371e7d478050119f7e2d58e3ef9 ./js/crypto-sha256-hmac.js
@@ -30,5 +30,6 @@ ca35b697d99cae4d1b60f2d60fcd37771987eb07 ./fonts/glyphicons-halflings-regular.w
de51a8494180a6db074af2dee2383f0a363c5b08 ./fonts/glyphicons-halflings-regular.svg de51a8494180a6db074af2dee2383f0a363c5b08 ./fonts/glyphicons-halflings-regular.svg
278e49a86e634da6f2a02f3b47dd9d2a8f26210f ./fonts/glyphicons-halflings-regular.woff 278e49a86e634da6f2a02f3b47dd9d2a8f26210f ./fonts/glyphicons-halflings-regular.woff
44bc1850f570972267b169ae18f1cb06b611ffa2 ./fonts/glyphicons-halflings-regular.ttf 44bc1850f570972267b169ae18f1cb06b611ffa2 ./fonts/glyphicons-halflings-regular.ttf
c024021c71cba503979a859d23cbf7a88b570d82 ./README.md ee481606d8d48f402d152fa632ba9e5f9da7f169 ./README.md
208b64a1ef61aaceec82f06515e4f7cf046793f6 ./index.html 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>