Compare commits

...

69 Commits
1.4a ... master

Author SHA1 Message Date
Kiyomichi Kosaka
2c8ee40a9a Make HD wallet compatible with wallets generated on https://bip32.org and bitcoin-cli. 2021-04-07 17:36:45 +02:00
OutCast3k
9a0175e18f added better error handling for when a payment fails on the #wallet page 2020-10-02 21:22:22 +00:00
OutCast3k
507b44f719 add transaction id reference to #newTransaction tab 2020-07-31 15:38:31 +00:00
OutCast3k
c868cf984e bug fix, changes to make double spending work on the transaction page from a transction id 2020-07-31 15:17:30 +00:00
root
b4fd55aebe added feature to rebuild a transaction from the txid, useful for RBF and double spending :o. Changed donation address. Released as version 1.6 2020-07-06 21:33:57 +00:00
root
f51be92a72 fixed multisig bug as described in issues/212 2020-07-05 20:21:41 +00:00
root
06cf50abb3 removed auto reload wallet feature. users must click or interact with the page. attempt to save on bandwidth. 2020-06-03 17:59:47 +00:00
root
35de4228d8 updated index.html to list link to new host 2020-04-22 20:18:08 +00:00
OutCast3k
a4ef169031 update sha1sum 2020-02-23 19:57:33 +00:00
OutCast3k
6bb5e3785a
Merge pull request #210 from junderw/patch-1
Don't add padding to P2WSH
2020-02-23 19:55:14 +00:00
OutCast3k
a199d3a55c
Merge pull request #208 from jmacxx/fix_bech32_address_decoding
fix: some bech32 addresses were not recognised
2020-02-23 19:54:46 +00:00
Jonathan Underwood
7e92530e1a
Don't add padding to P2WSH
Fixes #209
2020-02-20 10:12:57 +09:00
Wowee0
f5c2f48efc fix: some bech32 addresses were not recognised 2020-02-12 10:57:15 -06:00
OutCast3k
4f3ceeb3ea update date in sha1sum file 2019-12-28 12:10:39 +00:00
OutCast3k
73369dd253 add file hash of test.html to sha1sum 2019-12-28 12:08:51 +00:00
OutCast3k
6ed0d3e07e
Merge pull request #206 from jmacxx/tests
add some self-test routines to coinbin
2019-12-28 12:03:55 +00:00
Wowee0
84304f23ea tests added 2019-12-25 19:30:38 -06:00
OutCast3k
44ba1b3d30 update readme 2019-12-25 22:15:55 +00:00
OutCast3k
5583675390 custom hd key derivation addded 2019-12-25 22:10:55 +00:00
OutCast3k
56cb104ea4 updated sha1sum 2019-12-24 23:01:50 +00:00
OutCast3k
c6f70d000e
Merge pull request #194 from jmacxx/fix_issue_140
fix Issue 140: error logged to console when switching tabs.
2019-12-24 23:00:22 +00:00
OutCast3k
4836b20fae updated sha1sum 2019-12-24 22:47:28 +00:00
OutCast3k
f364ae4b4a
Merge pull request #198 from jmacxx/fix_issue_193
fix: RBF always set when redeeming OP_CHECKLOCKTIMEVERIFY
2019-12-24 22:44:43 +00:00
OutCast3k
64cb387247 updated as outcast3k 2019-12-24 21:53:20 +00:00
btc
b2a86006cf updated sha1sum file 2019-12-24 21:51:33 +00:00
OutCast3k
b5ebaafed8
Merge pull request #202 from junderw/fixScriptNum
Fix script num
2019-12-24 21:49:03 +00:00
kinoshitajona
d4f47fce28
Must do OPs with script method 2019-11-14 15:13:51 +09:00
kinoshitajona
5bd3786f94
Fix ScriptNum 2019-11-14 15:07:15 +09:00
Wowee0
b77f3cf06a fix: RBF always set when redeeming OP_CHECKLOCKTIMEVERIFY 2019-10-18 23:19:52 -05:00
Wowee0
b0c6c3a516 fix Uncaught TypeError logged to console when switching Tx Input and Output tabs 2019-09-23 21:01:03 -05:00
OutCast3k
a6f5dcf7f0 removed debugger code 2019-09-22 20:32:42 +00:00
OutCast3k
cf2a8b01cb update sha1sum file 2019-08-30 17:03:31 +00:00
OutCast3k
261c4ace40
Merge pull request #191 from Wowee0/choose_backend
fix for #189 .. three backend API options for btc/ltc/doge
2019-08-30 17:58:50 +01:00
Wowee0
e18b634c4e fix issue where empty broadcast did not handle the error response appropriately 2019-08-27 11:17:08 -05:00
Wowee0
1f3b878d63 bugfix for blockcypher when address used that has no UTXO 2019-08-22 07:41:36 -05:00
Wowee0
efc16c10fb allow backend API choice between blockcypher/blockchair/chain.so 2019-08-16 16:28:29 -05:00
Wowee0
477ca8890d
Merge pull request #1 from OutCast3k/master
sync with OutCast3k/coinbin
2019-06-15 09:18:15 -05:00
OutCast3k
e73e8093b3 change made to avoid captcha provided by cloudflare to TOR users 2019-06-05 19:34:45 +00:00
OutCast3k
40ea3230fd removed blockchain.com links 2019-05-28 15:21:58 +00:00
OutCast3k
dc416c6521 changes made to paper wallet 2019-05-24 14:44:47 +00:00
OutCast3k
fc66bc9423
Merge pull request #127 from olivergregorius/paperwallet
Paperwallet
2019-05-24 15:41:54 +01:00
OutCast3k
1c10bef510
Merge pull request #183 from yottalogical/blockchain-explorer-link
Add Link to Blockchain Explorer after Broadcasting Transaction (Litecoin)
2019-05-06 11:49:48 +01:00
yottalogical
b22e79391f
Update sha1sum 2019-05-05 12:36:32 -04:00
yottalogical
0be8fd9a97
Add link to blockchain explorer for Chain.so (Litecoin) 2019-05-05 12:30:28 -04:00
OutCast3k
1a364ff770 updated sha1sum file 2019-05-05 09:22:52 +00:00
OutCast3k
bc0c72117e
Merge pull request #182 from Wowee0/litecoin
re-enabled Litecoin
2019-05-05 10:11:31 +01:00
OutCast3k
13c50cf4b6
Merge pull request #170 from ivy-dong/ivy_remove_redundant_quotation_marks
remove redundant quotation marks
2019-05-05 10:09:08 +01:00
OutCast3k
dea1d1b274
Merge pull request #178 from yottalogical/blockchain-explorer-link 2019-05-05 10:07:00 +01:00
Wowee0
e6c70d133b set appropriate hrp for Litecoin SegWit addresses
set chain.so/address/LTC for view of address (previously was referencing BTC block explorer)
2019-04-22 22:09:20 -05:00
Wowee0
10aa011c6e LTC SegWit (pre-bech32) address version changed from 5 to 50 (i.e. 3-addresses changed to M-addresses) 2019-04-20 23:28:40 -05:00
Wowee0
c7a0fda7e5 re-enabled Litecoin 2019-04-19 10:40:59 -05:00
yottalogical
c9cfeefc86
Correct month in sha1sum 2019-02-22 18:19:35 -05:00
yottalogical
cdf4aa105b Fix variable name in broadcast success message 2019-02-06 15:43:23 -05:00
yottalogical
2fc574dde0 Remove unnecessary linebreak at end 2019-02-06 15:34:25 -05:00
yottalogical
f088ec2e52 Update sha1sum 2019-02-06 15:28:04 -05:00
yottalogical
9ccd73808d Capitalize TXID in success message 2019-02-06 15:23:09 -05:00
yottalogical
cb81362330 Add link to blockchain explorer for Cryptoid.info (Carboncoin) 2019-02-06 15:21:39 -05:00
yottalogical
fcbf25eaec Add link to blockchain explorer for coinb.in (Bitcoin) 2019-02-06 15:20:43 -05:00
yottalogical
2aca9ab28d Add link to blockchain explorer for Blockcypher.com 2019-02-06 14:46:19 -05:00
yottalogical
5c581316fe Add link to blockchain explorer for Chain.so (Bitcoin) 2019-02-06 14:39:48 -05:00
yottalogical
ebfb940dd5 Fix typo in comment 2019-02-06 14:32:49 -05:00
yottalogical
3201550d40 Add link to blockchain explorer for Chain.so (Dogecoin) 2019-02-06 14:23:27 -05:00
OutCast3k
d88ec3db4b update sha1sum file 2018-12-28 23:49:01 +00:00
OutCast3k
530453a701 improvement to previous timelock address bug fix 2018-12-28 23:42:00 +00:00
OutCast3k
194df37d56 bug fix for time locked addresses. transactions not being built correctly (no loss of funds!!!!) 2018-12-28 23:33:42 +00:00
Ivy Dong
87461b58b8 remove redundant quotation marks 2018-12-16 20:04:27 +08:00
OutCast3k
739aee3c0f couple of bug fixes with transaction building 2018-08-26 20:53:25 +00:00
oliverdorn
b997751791
Added functionality for printing Paper Wallet 2017-11-25 00:53:00 +01:00
oliverdorn
9bccc5c512
Added Buttons for printing Paper Wallets
Added Buttons for printint Paper Wallets for generated Legacy- and SegWit-Adresses
2017-11-25 00:49:16 +01:00
6 changed files with 855 additions and 144 deletions

View File

@ -1,7 +1,7 @@
coinbin
=======
A Open Source Browser Based Bitcoin Wallet. Version 1.4 beta by OutCast3k
A Open Source Browser Based Bitcoin Wallet. Version 1.6 beta by OutCast3k
Live version available at http://coinb.in/ or http://4zpinp6gdkjfplhk.onion
@ -24,12 +24,13 @@ Coinb.in supports a number of key features such as:
- Brain wallet support.
- Compatible with bitcoin-qt
- An offical .onion address for tor users.
- Offline qrcode creator and scanning tool
- HD (bip32) support
- Supports altcoins such as litecoin
- Replace by fee (RBF) Support
- Segwit Support
- Bech32 address support
- Offline qrcode creator and scanning tool.
- HD (bip32) support.
- Supports altcoins such as litecoin.
- Replace by fee (RBF) Support.
- Segwit Support.
- Bech32 address support.
- Fee calculator - https://coinb.in/#fees
- Transaction rebuild support for RBF and double spending.
Donate to 3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN to see more development!
Donate to 33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G to see more development!

View File

@ -338,7 +338,16 @@
</div>
<input type="button" class="btn btn-primary" value="Generate" id="newKeysBtn">
<div class="btn-group">
<input type="button" class="btn btn-primary" value="Generate" id="newKeysBtn">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a href="#" id="newPaperwalletBtn">Print</a></li>
</ul>
</div>
<br>
</div>
@ -383,7 +392,17 @@
<input type="text" class="form-control hidden" id="brainwalletSegWit">
</div>
<input type="button" class="btn btn-primary" value="Generate" id="newSegWitKeysBtn">
<div class="btn-group">
<input type="button" class="btn btn-primary" value="Generate" id="newSegWitKeysBtn">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li><a href="#" id="newSegwitPaperwalletBtn">Print</a></li>
</ul>
</div>
<br>
</div>
@ -578,7 +597,7 @@
<h2>Transaction <small>Create a new transaction</small></h2>
<p>Use this page to create a raw transaction</p>
<b>Address, WIF key or Redeem Script</b>:
<b>Address, WIF key, Redeem Script or Transaction ID</b>:
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-info qrcodeScanner" type="button" data-toggle="modal" data-target="#modalQrcodeScanner" forward-result="#redeemFrom"><span class="glyphicon glyphicon-camera"></span></button>
@ -609,7 +628,7 @@
<label>Null Data</label> <span class="text-muted text-normal">(80 byte limit, <i>40 bytes recommended</i>)</span>
<p class="checkbox">
<label><input type="checkbox" id="opReturn" class="checkbox-inline"> Allow data to be sent within the transaction and stored in the blockchain by using <a href="https://bitcoin.org/en/developer-guide#null-data" target="_"blank">OP_RETURN</a>.</label>
<label><input type="checkbox" id="opReturn" class="checkbox-inline"> Allow data to be sent within the transaction and stored in the blockchain by using <a href="https://bitcoin.org/en/developer-guide#null-data" target="_blank">OP_RETURN</a>.</label>
<div class="text-muted">When using this option you may enter a hex string or address into the address field on the output tab.</div>
</p>
@ -624,7 +643,7 @@
<label>Replace By Fee (RBF)</label>
<p class="checkbox">
<label><input type="checkbox" id="txRBF" class="checkbox-inline"> Make this a <a href="https://en.bitcoin.it/wiki/Transaction_replacement" target="_blank">RBF transaction</a>.</label>
<label><input type="checkbox" id="txRBF" class="checkbox-inline" checked> Make this a <a href="https://en.bitcoin.it/wiki/Transaction_replacement" target="_blank">RBF transaction</a>.</label>
</p>
<hr>
@ -1174,18 +1193,26 @@
<div class="row">
<div class="col-md-8">
<b>Path</b><br>
<select class="form-control">
<option>Simple: m/i</option>
<select class="form-control" id="hdpathtype">
<option value="simple">Simple: m/i</option>
<option value="custom">Custom</option>
</select>
<div id="hdpath" class="hidden" style="margin-top:4px">
<span class="input-group">
<input type="text" class="form-control" value="m/0/1" title="WARNING: see #settings page when using hardened paths!"> <br>
<span class="input-group-addon"> / </span>
</span>
</div>
</div>
<div class="col-md-2">
<b>Index (Start)</b><br>
<b><u>I</u>ndex (Start)</b><br>
<input type="text" class="form-control derivation_index_start" value="0">
</div>
<div class="col-md-2">
<b>Index (End)</b><br>
<b><u>I</u>ndex (End)</b><br>
<input type="text" class="form-control derivation_index_end" value="1">
</div>
@ -1306,7 +1333,7 @@
<div class="tab-pane tab-content" id="about">
<h2>About <small>open source bitcoin wallet</small></h2>
<p>Version 1.4</p>
<p>Version 1.6</p>
<p>Compatible with bitcoin core</p>
<p>Github <a href="https://github.com/OutCast3k/coinbin/">https://github.com/OutCast3k/coinbin/</a></p>
<p>TOR <a href="http://4zpinp6gdkjfplhk.onion">4zpinp6gdkjfplhk.onion</a></p>
@ -1316,12 +1343,13 @@
<h3>Information</h3>
<p>Coinb.in is a free and open source project released under the MIT license, originally by <a href="https://bitcointalk.org/index.php?action=profile;u=34834" target="_blank">OutCast3k</a> in 2013. Discussion of the project can be found at <a href="https://bitcointalk.org/index.php?topic=390046" target="_blank">bitcointalk.org</a> during its early testing stages when its primary focus was to develop a proof of concept multisig solution in javascript.</p>
<p>Coinb.in is run and funded by the generosity of others in terms of <a href="https://github.com/OutCast3k/coinbin/graphs/contributors" target="_blank">development</a> and hosting.</p>
<p>Coinb.in is kindly hosted by <a href="https://www.bitvps.com/" target="_blank">BitVPS.com</a>.</p>
<h3>Privacy</h3>
<p>Coinb.in believes strongly in privacy, not only do we support the use of TOR, the site does not collect and store IP or transaction data via our servers nor do we store your bitcoins private key. We do route traffic via cloudflare using an SSL certificate.</p>
<h3>Support</h3>
<p>We recommend that you first check our <a href="https://status.coinb.in/" target="_blank">service status</a> page and then <a href="https://blog.coinb.in/" target="_blank">blog</a> page which has multiple <a href="https://blog.coinb.in/guides" target="_blank">guides</a>. However if the problem persists you can contact us by emailing support{at}coinb.in.</p>
<h3>Donate</h3>
<p>Please donate to <a href="bitcoin:3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN">3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN</a> if you found this project useful or want to see more features!</p>
<p>Please donate to <a href="bitcoin:33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G">33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G</a> if you found this project useful or want to see more features!</p>
</div>
<div class="tab-pane tab-content" id="settings">
@ -1334,7 +1362,8 @@
<p class="text-muted">Select which network you'd like to use for key pair generation.</p>
<select class="form-control" id="coinjs_coin">
<option value="bitcoin_mainnet" rel="0x00;0x80;0x05;0x488b21e;0x488ade4;coinb.in;coinb.in">Bitcoin (mainnet)</option>
<option value="dogecoin_mainnet" rel="0x1e;0x9e;0x16;0x0827421e;0x089944e4;chain.so_dogecoin;chain.so_dogecoin">Dogecoin (mainnet)</option>
<option value="litecoin_mainnet" rel="0x30;0xb0;0x32;0x019da462;0x019d9cfe;blockcypher_litecoin;blockcypher_litecoin">Litecoin (mainnet)</option>
<option value="dogecoin_mainnet" rel="0x1e;0x9e;0x16;0x0827421e;0x089944e4;blockcypher_dogecoin;blockcypher_dogecoin">Dogecoin (mainnet)</option>
<option value="carboncoin_mainnet" rel="0x2f;0xaf;0x05;0x488b21e;0x488ade4;cryptoid.info_carboncoin;cryptoid.info_carboncoin">Carboncoin (mainnet)</option>
<option value="shadowcash_mainnet" rel="0x3f;0xbf;0x7d;0xee80286a;0xee8031e8;false;false">ShadowCash (mainnet)</option>
<option value="bitcoin_testnet" rel="0x6f;0xef;0xc4;0x043587cf;0x04358394;false;false">Bitcoin (testnet)</option>
@ -1391,8 +1420,14 @@
<p class="text-muted">Select the network you wish to broadcast the transaction via</p>
<select class="form-control" id="coinjs_broadcast">
<option value="coinb.in">coinb.in (Bitcoin mainnet)</option>
<option value="chain.so_bitcoinmainnet"> Chain.so (Bitcoin mainnet)</option>
<option value="blockcypher_bitcoinmainnet"> Blockcypher.com (Bitcoin mainnet)</option>
<option value="blockcypher_litecoin"> Blockcypher.com (Litecoin)</option>
<option value="blockcypher_dogecoin"> Blockcypher.com (Dogecoin)</option>
<option value="blockchair_bitcoinmainnet"> Blockchair.com (Bitcoin mainnet)</option>
<option value="blockchair_litecoin"> Blockchair.com (Litecoin)</option>
<option value="blockchair_dogecoin"> Blockchair.com (Dogecoin)</option>
<option value="chain.so_bitcoinmainnet"> Chain.so (Bitcoin mainnet)</option>
<option value="chain.so_litecoin"> Chain.so (Litecoin)</option>
<option value="chain.so_dogecoin"> Chain.so (Dogecoin)</option>
<option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option>
</select>
@ -1407,6 +1442,13 @@
<p class="text-muted">Select the network you wish to retreive your unspent inputs from</p>
<select class="form-control" id="coinjs_utxo">
<option value="coinb.in">coinb.in (Bitcoin mainnet)</option>
<option value="blockcypher_bitcoinmainnet"> Blockcypher.com (Bitcoin mainnet)</option>
<option value="blockcypher_litecoin"> Blockcypher.com (Litecoin)</option>
<option value="blockcypher_dogecoin"> Blockcypher.com (Dogecoin)</option>
<option value="blockchair_bitcoinmainnet"> Blockchair.com (Bitcoin mainnet)</option>
<option value="blockchair_litecoin"> Blockchair.com (Litecoin)</option>
<option value="blockchair_dogecoin"> Blockchair.com (Dogecoin)</option>
<option value="chain.so_bitcoinmainnet"> Chain.so (Bitcoin mainnet)</option>
<option value="chain.so_litecoin"> Chain.so (Litecoin)</option>
<option value="chain.so_dogecoin"> Chain.so (Dogecoin)</option>
<option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option>
@ -1414,6 +1456,19 @@
</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>
<div id="statusSettings" class="hidden alert">
@ -1433,7 +1488,7 @@
<div id="footer">
<div class="container text-right">
<p class="text-muted">Version 1.4</p>
<p class="text-muted">Version 1.6</p>
</div>
</div>

View File

@ -18,11 +18,14 @@
coinjs.compressed = false;
coinjs.hd_derivation = "bip32_derivation";
/* other vars */
coinjs.developer = '3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN'; //bitcoin
coinjs.developer = '33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G'; //bitcoin
/* bit(coinb.in) api vars */
coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+'coinb.in/api/';
coinjs.hostname = ((document.location.hostname.split(".")[(document.location.hostname.split(".")).length-1]) == 'onion') ? '4zpinp6gdkjfplhk.onion' : 'coinb.in';
coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+coinjs.hostname+'/api/';
coinjs.uid = '1';
coinjs.key = '12345678901234567890123456789012';
@ -155,7 +158,11 @@
}
var s = coinjs.script();
s.writeBytes(coinjs.numToByteArray(checklocktimeverify));
if (checklocktimeverify <= 16 && checklocktimeverify >= 1) {
s.writeOp(0x50 + checklocktimeverify);//OP_1 to OP_16 for minimal encoding
} else {
s.writeBytes(coinjs.numToScriptNumBytes(checklocktimeverify));
}
s.writeOp(177);//OP_CHECKLOCKTIMEVERIFY
s.writeOp(117);//OP_DROP
s.writeBytes(Crypto.util.hexToBytes(pubkey));
@ -198,7 +205,7 @@
var decode = coinjs.bech32_decode(address);
if(decode){
decode.data.shift();
return Crypto.util.bytesToHex(coinjs.bech32_convert(decode.data, 5, 8, true));
return Crypto.util.bytesToHex(coinjs.bech32_convert(decode.data, 5, 8, false));
}
return r;
}
@ -302,7 +309,7 @@
return o;
} else {
return false;
throw "Invalid checksum";
}
} catch(e) {
bech32rs = coinjs.bech32redeemscript(addr);
@ -633,6 +640,8 @@
coinjs.compressed = c; // reset to default
}
return r;
}
// extend prv/pub key
@ -646,10 +655,43 @@
'pubkey':this.keys.pubkey});
}
// derive from path
r.derive_path = function(path) {
if( path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'' ) return this;
var p = path.split('/');
var hdp = coinjs.clone(this); // clone hd path
for( var i in p ) {
if((( i == 0 ) && c != 'm') || i == 'remove'){
continue;
}
var c = p[i];
var use_private = (c.length > 1) && (c[c.length-1] == '\'');
var child_index = parseInt(use_private ? c.slice(0, c.length - 1) : c) & 0x7fffffff;
if(use_private)
child_index += 0x80000000;
hdp = hdp.derive(child_index);
var key = ((hdp.keys_extended.privkey) && hdp.keys_extended.privkey!='') ? hdp.keys_extended.privkey : hdp.keys_extended.pubkey;
hdp = coinjs.hd(key);
}
return hdp;
}
// derive key from index
r.derive = function(i){
i = (i)?i:0;
var blob = (Crypto.util.hexToBytes(this.keys.pubkey)).concat(coinjs.numToBytes(i,4).reverse());
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 hash = j.getHMAC(Crypto.util.bytesToHex(r.chain_code), "HEX", "SHA-512", "HEX");
@ -702,7 +744,6 @@
o.parent_fingerprint = (ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(r.keys.pubkey),{asBytes:true}),{asBytes:true})).slice(0,4);
o.keys_extended = o.extend();
return o;
}
@ -767,8 +808,7 @@
return o;
}
r.parse();
return r;
return r.parse();
}
@ -846,6 +886,9 @@
var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired);
r.address = multi['address'];
r.type = 'multisig__'; // using __ for now to differentiat from the other object .type == "multisig"
var rs = Crypto.util.bytesToHex(s.buffer);
r.redeemscript = rs;
} else if((s.chunks.length==2) && (s.buffer[0] == 0 && s.buffer[1] == 20)){ // SEGWIT
r = {};
r.type = "segwit__";
@ -859,6 +902,8 @@
r.pubkey = Crypto.util.bytesToHex(s.chunks[3]);
r.checklocktimeverify = coinjs.bytesToNum(s.chunks[0].slice());
r.address = coinjs.simpleHodlAddress(r.pubkey, r.checklocktimeverify).address;
var rs = Crypto.util.bytesToHex(s.buffer);
r.redeemscript = rs;
r.type = "hodl__";
}
} catch(e) {
@ -1028,6 +1073,11 @@
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=unspent&address='+address+'&r='+Math.random(), callback, "GET");
}
/* list transaction data */
r.getTransaction = function(txid, callback) {
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=bitcoin&request=gettransaction&txid='+txid+'&r='+Math.random(), callback, "GET");
}
/* add unspent to transaction */
r.addUnspent = function(address, callback, script, segwit, sequence){
var self = this;
@ -1048,32 +1098,37 @@
var unspent = xmlDoc.getElementsByTagName("unspent")[0];
for(i=1;i<=unspent.childElementCount;i++){
var u = xmlDoc.getElementsByTagName("unspent_"+i)[0]
var txhash = (u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue).match(/.{1,2}/g).reverse().join("")+'';
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
if(unspent){
for(i=1;i<=unspent.childElementCount;i++){
var u = xmlDoc.getElementsByTagName("unspent_"+i)[0]
var txhash = (u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue).match(/.{1,2}/g).reverse().join("")+'';
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
if(segwit){
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
It is not standard and removed during the signing procedure. */
if(segwit){
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
It is not standard and removed during the signing procedure. */
s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(script));
s.writeOp(0);
s.writeBytes(coinjs.numToBytes(u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1, 8));
scr = Crypto.util.bytesToHex(s.buffer);
s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(script));
s.writeOp(0);
s.writeBytes(coinjs.numToBytes(u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1, 8));
scr = Crypto.util.bytesToHex(s.buffer);
}
var seq = sequence || false;
self.addinput(txhash, n, scr, seq);
value += u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1;
total++;
}
var seq = sequence || false;
self.addinput(txhash, n, scr, seq);
value += u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1;
total++;
}
x.unspent = $(xmlDoc).find("unspent");
x.result = xmlDoc.getElementsByTagName("result")[0].childNodes[0].nodeValue;
x.unspent = unspent;
x.value = value;
x.total = total;
x.response = xmlDoc.getElementsByTagName("response")[0].childNodes[0].nodeValue;
return callback(x);
});
}
@ -1297,7 +1352,14 @@
return {'type':'segwit', 'signed':signed, 'signatures': sigs, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[0]), 'value': value};
} else if (this.ins[index].script.chunks[0]==0 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1][this.ins[index].script.chunks[this.ins[index].script.chunks.length-1].length-1]==174) { // OP_CHECKMULTISIG
// multisig script, with signature(s) included
return {'type':'multisig', 'signed':'true', 'signatures':this.ins[index].script.chunks.length-2, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])};
sigcount = 0;
for(i=1; i<this.ins[index].script.chunks.length-1;i++){
if(this.ins[index].script.chunks[i]!=0){
sigcount++;
}
}
return {'type':'multisig', 'signed':'true', 'signatures':sigcount, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])};
} else if (this.ins[index].script.chunks[0]>=80 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]==174) { // OP_CHECKMULTISIG
// multisig script, without signature!
return {'type':'multisig', 'signed':'false', 'signatures':0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
@ -1918,12 +1980,31 @@
}
}
coinjs.numToByteArray = function(num) {
if (num <= 256) {
return [num];
} else {
return [num % 256].concat(coinjs.numToByteArray(Math.floor(num / 256)));
function scriptNumSize(i) {
return i > 0x7fffffff ? 5
: i > 0x7fffff ? 4
: i > 0x7fff ? 3
: i > 0x7f ? 2
: i > 0x00 ? 1
: 0;
}
coinjs.numToScriptNumBytes = function(_number) {
var value = Math.abs(_number);
var size = scriptNumSize(value);
var result = [];
for (var i = 0; i < size; ++i) {
result.push(0);
}
var negative = _number < 0;
for (i = 0; i < size; ++i) {
result[i] = value & 0xff;
value = Math.floor(value / 256);
}
if (negative) {
result[size - 1] |= 0x80;
}
return result;
}
coinjs.numToVarInt = function(num) {

View File

@ -65,7 +65,6 @@ $(document).ready(function() {
$("#openWallet").removeClass("hidden").show();
walletBalance();
checkBalanceLoop();
} else {
$("#openLoginStatus").html("Your passwords do not match!").removeClass("hidden").fadeOut().fadeIn();
}
@ -133,7 +132,7 @@ $(document).ready(function() {
$("#walletSpend").removeClass("hidden").addClass("hidden");
});
$("#walletBalance").click(function(){
$("#walletBalance, #walletAddress, #walletQrCode").click(function(){
walletBalance();
});
@ -171,7 +170,7 @@ $(document).ready(function() {
script = sw.redeemscript;
}
var sequence = false;
var sequence = 0xffffffff-1;
if($("#walletRBF").is(":checked")){
sequence = 0xffffffff-2;
}
@ -297,28 +296,20 @@ $(document).ready(function() {
});
function walletBalance(){
var tx = coinjs.transaction();
$("#walletLoader").removeClass("hidden");
coinjs.addressBalance($("#walletAddress").html(),function(data){
if($(data).find("result").text()==1){
var v = $(data).find("balance").text()/100000000;
$("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn();
} else {
if($("#walletLoader").hasClass("hidden")){
var tx = coinjs.transaction();
$("#walletLoader").removeClass("hidden");
coinjs.addressBalance($("#walletAddress").html(),function(data){
if($(data).find("result").text()==1){
var v = $(data).find("balance").text()/100000000;
$("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn();
} else {
$("#walletBalance").html("0.00 BTC").attr('rel',v).fadeOut().fadeIn();
}
}
$("#walletLoader").addClass("hidden");
});
}
function checkBalanceLoop(){
clearTimeout(wallet_timer);
wallet_timer = setTimeout(function(){
if($("#walletLoader").hasClass("hidden")){
walletBalance();
}
checkBalanceLoop();
},45000);
$("#walletLoader").addClass("hidden");
});
}
}
/* new -> address code */
@ -344,7 +335,22 @@ $(document).ready(function() {
$("#aes256passStatus").removeClass("hidden");
}
$("#newPrivKeyEnc").val(CryptoJS.AES.encrypt(coin.wif, $("#aes256pass").val())+'');
});
$("#newPaperwalletBtn").click(function(){
if($("#newBitcoinAddress").val()==""){
$("#newKeysBtn").click();
}
var paperwallet = window.open();
paperwallet.document.write('<h2>BTC PaperWallet</h2><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Address (Share)</h3></div><div style="text-align: center;"><div id="qraddress"></div><p>'+$("#newBitcoinAddress").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Public Key</h3></div><div style="text-align: center;"><div id="qrpubkey"></div><p>'+$("#newPubKey").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Private Key (KEEP SECRET!)</h3></div><div style="text-align: center;"><div id="qrprivkey"></div><p>'+$("#newPrivKey").val()+'</p></div></div>');
paperwallet.document.close();
paperwallet.focus();
new QRCode(paperwallet.document.getElementById("qraddress"), {text: $("#newBitcoinAddress").val(), width: 125, height: 125});
new QRCode(paperwallet.document.getElementById("qrpubkey"), {text: $("#newPubKey").val(), width: 125, height: 125});
new QRCode(paperwallet.document.getElementById("qrprivkey"), {text: $("#newPrivKey").val(), width: 125, height: 125});
paperwallet.print();
paperwallet.close();
});
$("#newBrainwallet").click(function(){
@ -392,6 +398,22 @@ $(document).ready(function() {
coinjs.compressed = compressed;
});
$("#newSegwitPaperwalletBtn").click(function(){
if($("#newSegWitAddress").val()==""){
$("#newSegWitKeysBtn").click();
}
var paperwallet = window.open();
paperwallet.document.write('<h2>BTC SegWit PaperWallet</h2><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Address (Share)</h3></div><div style="text-align: center;"><div id="qraddress"></div><p>'+$("#newSegWitAddress").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Public Key</h3></div><div style="text-align: center;"><div id="qrpubkey"></div><p>'+$("#newSegWitPubKey").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Redeem Script</h3></div><div style="text-align: center;"><div id="qrredeem"></div><p>'+$("#newSegWitRedeemScript").val()+'</p></div></div><hr><div style="margin-top: 5px; margin-bottom: 5px"><div><h3 style="margin-top: 0">Private Key (KEEP SECRET!)</h3></div><div style="text-align: center;"><div id="qrprivkey"></div><p>'+$("#newSegWitPrivKey").val()+'</p></div></div>');
paperwallet.document.close();
paperwallet.focus();
new QRCode(paperwallet.document.getElementById("qraddress"), {text: $("#newSegWitAddress").val(), width: 110, height: 110});
new QRCode(paperwallet.document.getElementById("qrpubkey"), {text: $("#newSegWitPubKey").val(), width: 110, height: 110});
new QRCode(paperwallet.document.getElementById("qrredeem"), {text: $("#newSegWitRedeemScript").val(), width: 110, height: 110});
new QRCode(paperwallet.document.getElementById("qrprivkey"), {text: $("#newSegWitPrivKey").val(), width: 110, height: 110});
paperwallet.print();
paperwallet.close();
});
/* new -> multisig code */
@ -625,7 +647,7 @@ $(document).ready(function() {
}
if(!$(o).hasClass("has-error")){
var seq = null;
var seq = 0xffffffff-1;
if($("#txRBF").is(":checked")){
seq = 0xffffffff-2;
}
@ -854,12 +876,12 @@ $(document).ready(function() {
/* redeem from button code */
$("#redeemFromBtn").click(function(){
var redeem = redeemingFrom($("#redeemFrom").val());
var redeem = redeemingFrom($("#redeemFrom").val());
$("#redeemFromStatus, #redeemFromAddress").addClass('hidden');
if(redeem.from=='multisigAddress'){
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> You should use the redeem script, not the multisig address!');
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> You should use the redeem script, not its address!');
return false;
}
@ -876,11 +898,32 @@ $(document).ready(function() {
var host = $(this).attr('rel');
// api: blockcypher blockchair chain.so
// network name "btc" "bitcoin" "BTC"
// network name "ltc" "litecoin" "LTC"
// network name "doge" "dogecoin" "DOGE"
if(host=='chain.so_litecoin'){
listUnspentChainso_Litecoin(redeem);
if(host=='chain.so_bitcoinmainnet'){
listUnspentChainso(redeem, "BTC");
} else if(host=='chain.so_litecoin'){
listUnspentChainso(redeem, "LTC");
} else if(host=='chain.so_dogecoin'){
listUnspentChainso_Dogecoin(redeem);
listUnspentChainso(redeem, "DOGE");
} else if(host=='blockcypher_bitcoinmainnet'){
listUnspentBlockcypher(redeem, "btc");
} else if(host=='blockcypher_litecoin'){
listUnspentBlockcypher(redeem, "ltc");
} else if(host=='blockcypher_dogecoin'){
listUnspentBlockcypher(redeem, "doge");
} else if(host=='blockchair_bitcoinmainnet'){
listUnspentBlockchair(redeem, "bitcoin");
} else if(host=='blockchair_litecoin'){
listUnspentBlockchair(redeem, "litecoin");
} else if(host=='blockchair_dogecoin'){
listUnspentBlockchair(redeem, "dogecoin");
} else if(host=='cryptoid.info_carboncoin'){
listUnspentCryptoidinfo_Carboncoin(redeem);
} else {
@ -889,8 +932,8 @@ $(document).ready(function() {
if($("#redeemFromStatus").hasClass("hidden")) {
// An ethical dilemma: Should we automatically set nLockTime?
if(redeem.from == 'redeemScript' && redeem.decodedRs.type == "hodl__") {
$("#nLockTime").val(redeem.decodedRs.checklocktimeverify);
if(redeem.from == 'redeemScript' && redeem.type == "hodl__") {
$("#nLockTime").val(redeem.decodescript.checklocktimeverify);
} else {
$("#nLockTime").val(0);
}
@ -926,11 +969,19 @@ $(document).ready(function() {
r.addr = decodeRs['address'];
r.from = 'redeemScript';
r.decodedRs = decodeRs.redeemscript;
r.type = decodeRs['type'];
r.redeemscript = true;
r.decodescript = decodeRs;
} else { // something else
r.addr = '';
r.from = 'other';
r.redeemscript = false;
if(string.match(/^[a-f0-9]{64}$/i)){
r.addr = string;
r.from = 'txid';
r.redeemscript = false;
} else {
r.addr = '';
r.from = 'other';
r.redeemscript = false;
}
}
}
return r;
@ -997,9 +1048,59 @@ $(document).ready(function() {
}
}
/* global function to add inputs to page */
function addInput(address, amount) {
if($("#recipients .recipient:last .address:last").val() != ""){
$("#recipients .addressAddTo:first").click();
};
$("#recipients .address:last").val(address);
$("#recipients .amount:last").val(amount);
}
/* default function to retreive unspent outputs*/
function listUnspentDefault(redeem){
var tx = coinjs.transaction();
// unspent from transaction; double spend and RBF.
if(redeem.from == 'txid'){
tx.getTransaction(redeem.addr, function(data){
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Attempted to rebuild transaction id <a href="'+explorer_tx+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
$.each($(data).find("inputs").children(), function(i,o){
var tx = $(o).find("txid").text();
var n = $(o).find("output_no").text();
var amount = (($(o).find("value").text()*1)).toFixed(8);
var scr = $(o).find("script").text();
addOutput(tx, n, scr, amount);
});
$("#recipients .addressRemoveTo").click();
$("#recipients .address").val("");
$("#recipients .amount").val("");
$.each($(data).find("outputs").children(), function(i,o){
addInput($(o).find("address").text(), $(o).find("value").text());
});
$("#redeemFromBtn").html("Load").attr('disabled',false);
totalInputAmount();
validateOutputAmount();
});
return;
}
// unspent from address
tx.listUnspent(redeem.addr, function(data){
if(redeem.addr) {
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
@ -1022,25 +1123,27 @@ $(document).ready(function() {
}
/* retrieve unspent data from chainso for litecoin */
function listUnspentChainso_Litecoin(redeem){
/* retrieve unspent data from blockcypher */
function listUnspentBlockcypher(redeem,network){
$.ajax ({
type: "GET",
url: "https://chain.so/api/v2/get_tx_unspent/ltc/"+redeem.addr,
url: "https://api.blockcypher.com/v1/"+network+"/main/addrs/"+redeem.addr+"?includeScript=true&unspentOnly=true",
dataType: "json",
error: function(data) {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
},
success: function(data) {
if((data.status && data.data) && data.status=='success'){
if (data.address) { // address field will always be present, txrefs is only present if there are UTXOs
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
for(var i in data.data.txs){
var o = data.data.txs[i];
var tx = ((o.txid).match(/.{1,2}/g).reverse()).join("")+'';
var n = o.output_no;
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o.script_hex;
var amount = o.value;
addOutput(tx, n, script, amount);
for(var i in data.txrefs){
var o = data.txrefs[i];
var tx = ((""+o.tx_hash).match(/.{1,2}/g).reverse()).join("")+'';
if(tx.match(/^[a-f0-9]+$/)){
var n = o.tx_output_n;
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o.script;
var amount = ((o.value.toString()*1)/100000000).toFixed(8);
addOutput(tx, n, script, amount);
}
}
} else {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.');
@ -1087,19 +1190,54 @@ $(document).ready(function() {
}
/* retrieve unspent data from chain.so for dogecoin */
function listUnspentChainso_Dogecoin(redeem){
/* retrieve unspent data from blockchair */
function listUnspentBlockchair(redeem,network){
$.ajax ({
type: "GET",
url: "https://chain.so/api/v2/get_tx_unspent/doge/"+redeem.addr,
url: "https://api.blockchair.com/"+network+"/dashboards/address/"+redeem.addr,
dataType: "json",
error: function(data) {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
},
success: function(data) {
if((data.context && data.data) && data.context.code =='200'){
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
var all_info = data.data[redeem.addr];
for(var i in all_info.utxo){
var o = all_info.utxo[i];
var tx = ((""+o.transaction_hash).match(/.{1,2}/g).reverse()).join("")+'';
if(tx.match(/^[a-f0-9]+$/)){
var n = o.index;
var script = (redeem.redeemscript==true) ? redeem.decodedRs : all_info.address.script_hex;
var amount = ((o.value.toString()*1)/100000000).toFixed(8);
addOutput(tx, n, script, amount);
}
}
} else {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.');
}
},
complete: function(data, status) {
$("#redeemFromBtn").html("Load").attr('disabled',false);
totalInputAmount();
}
});
}
/* retrieve unspent data from chainso */
function listUnspentChainso(redeem, network){
$.ajax ({
type: "GET",
url: "https://chain.so/api/v2/get_tx_unspent/"+network+"/"+redeem.addr,
dataType: "json",
error: function(data) {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
},
success: function(data) {
if((data.status && data.data) && data.status=='success'){
$("#redeemFromAddress").removeClass('hidden').html(
'<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
for(var i in data.data.txs){
var o = data.data.txs[i];
var tx = ((""+o.txid).match(/.{1,2}/g).reverse()).join("")+'';
@ -1121,6 +1259,7 @@ $(document).ready(function() {
});
}
/* math to calculate the inputs and outputs */
function totalInputAmount(){
@ -1180,7 +1319,7 @@ $(document).ready(function() {
rawSubmitDefault(this);
});
// broadcast transaction vai coinbin (default)
// broadcast transaction via coinbin (default)
function rawSubmitDefault(btn){
var thisbtn = btn;
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
@ -1195,8 +1334,7 @@ $(document).ready(function() {
success: function(data) {
$("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden');
if($(data).find("result").text()==1){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger');
$("#rawTransactionStatus").html('txid: '+$(data).find("txid").text());
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' TXID: ' + $(data).find("txid").text() + '<br> <a href="https://coinb.in/tx/' + $(data).find("txid").text() + '" target="_blank">View on Blockchain</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
}
@ -1222,8 +1360,7 @@ $(document).ready(function() {
success: function(data) {
$("#rawTransactionStatus").html(unescape($(data).find("response").text()).replace(/\+/g,' ')).removeClass('hidden');
if($(data).find("result").text()==1){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger');
$("#rawTransactionStatus").html('txid: '+$(data).find("txid").text());
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' TXID: ' + $(data).find("txid").text() + '<br> <a href="https://chainz.cryptoid.info/carbon/tx.dws?' + $(data).find("txid").text() + '" target="_blank">View on Blockchain Explorer</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
}
@ -1236,11 +1373,11 @@ $(document).ready(function() {
}
// broadcast transaction via chain.so (mainnet)
function rawSubmitChainso_BitcoinMainnet(thisbtn){
function rawSubmitChainso(thisbtn, network){
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://chain.so/api/v2/send_tx/BTC/",
url: "https://chain.so/api/v2/send_tx/"+network+"/",
data: {"tx_hex":$("#rawTransaction").val()},
dataType: "json",
error: function(data) {
@ -1252,7 +1389,7 @@ $(document).ready(function() {
},
success: function(data) {
if(data.status && data.data.txid){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.data.txid);
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' TXID: ' + data.data.txid + '<br> <a href="https://chain.so/tx/'+network+'/' + data.data.txid + '" target="_blank">View on Blockchain Explorer</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
@ -1265,22 +1402,20 @@ $(document).ready(function() {
}
// broadcast transaction via blockcypher.com (mainnet)
function rawSubmitblockcypher_BitcoinMainnet(thisbtn){
function rawSubmitblockcypher(thisbtn, network){
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://api.blockcypher.com/v1/btc/main/txs/push",
url: "https://api.blockcypher.com/v1/"+network+"/main/txs/push",
data: JSON.stringify({"tx":$("#rawTransaction").val()}),
error: function(data) {
var obj = $.parseJSON(data.responseText);
var r = ' ';
r += (obj.error) ? obj.error : '';
r = (r!='') ? r : ' Failed to broadcast'; // build response
var r = 'Failed to broadcast: error code=' + data.status.toString() + ' ' + data.statusText;
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
},
success: function(data) {
if((data.tx) && data.tx.hash){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.tx.hash);
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden")
.html(' TXID: ' + data.tx.hash + '<br> <a href="https://live.blockcypher.com/'+network+'/tx/' + data.tx.hash + '" target="_blank">View on Blockchain Explorer</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
@ -1292,27 +1427,24 @@ $(document).ready(function() {
});
}
// broadcast transaction via chain.so for dogecoin
function rawSubmitchainso_dogecoin(thisbtn){
// broadcast transaction via blockchair
function rawSubmitblockchair(thisbtn, network){
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://chain.so/api/v2/send_tx/DOGE",
data: {"tx_hex":$("#rawTransaction").val()},
url: "https://api.blockchair.com/"+network+"/push/transaction",
data: {"data":$("#rawTransaction").val()},
dataType: "json",
error: function(data) {
var obj = $.parseJSON(data.responseText);
var r = ' ';
r += (obj.data.tx_hex) ? ' '+obj.data.tx_hex : '';
r = (r!='') ? r : ' Failed to broadcast'; // build response
var r = 'Failed to broadcast: error code=' + data.status.toString() + ' ' + data.statusText;
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
// console.error(JSON.stringify(data, null, 4));
},
success: function(data) {
// console.info(JSON.stringify(data, null, 4));
if((data.status && data.data) && data.status=='success'){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: ' + data.data.txid);
if((data.context && data.data) && data.context.code=='200'){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden")
.html(' TXID: ' + data.data.transaction_hash + '<br> <a href="https://blockchair.com/'+network+'/transaction/' + data.data.transaction_hash + '" target="_blank">View on Blockchain Explorer</a>');
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
@ -1569,12 +1701,24 @@ $(document).ready(function() {
function deriveHDaddress() {
var hd = coinjs.hd($("#verifyHDaddress .hdKey").html());
var index_start = $("#verifyHDaddress .derivation_index_start").val()*1;
var index_end = $("#verifyHDaddress .derivation_index_end").val()*1;
var index_start = $("#verifyHDaddress .derivation_index_start").val();
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 = '';
$("#verifyHDaddress .derived_data table tbody").html("");
for(var i=index_start;i<=index_end;i++){
var derived = hd.derive(i);
if($("#hdpathtype option:selected").val()=='simple'){
var derived = hd.derive(i);
} else {
var derived = hd.derive_path(($("#hdpath input").val().replace(/\/+$/, ""))+'/'+i+use_private_index);
}
html += '<tr>';
html += '<td>'+i+'</td>';
html += '<td><input type="text" class="form-control" value="'+derived.keys.address+'" readonly></td>';
@ -1587,6 +1731,15 @@ $(document).ready(function() {
}
$("#hdpathtype").change(function(){
if($(this).val()=='simple'){
$("#hdpath").removeClass().addClass("hidden");
} else {
$("#hdpath").removeClass();
}
});
/* sign code */
$("#signBtn").click(function(){
@ -1717,7 +1870,7 @@ $(document).ready(function() {
$('a[data-toggle="tab"]').on('click', function(e) {
e.preventDefault();
if(e.target){
if(e.target && $(e.target).attr('href')) {
history.pushState(null, null, '#'+$(e.target).attr('href').substr(1));
}
});
@ -1769,9 +1922,19 @@ $(document).ready(function() {
coinjs.hdkey.pub = $("#coinjs_hdpub").val()*1;
coinjs.hdkey.prv = $("#coinjs_hdprv").val()*1;
coinjs.hd_derivation = $("#coinjs_derivation").val();
configureBroadcast();
configureGetUnspentTx();
if (coinjs.pub == 0x30){ // LTC
explorer_addr = "https://chain.so/address/LTC/";
coinjs.bech32.hrp = "ltc";
}
else if (coinjs.pub == 0x1e){ // DOGE
explorer_addr = "https://chain.so/address/DOGE/";
}
$("#statusSettings").addClass("alert-success").removeClass("hidden").html("<span class=\"glyphicon glyphicon-ok\"></span> Settings updates successfully").fadeOut().fadeIn();
} else {
$("#statusSettings").addClass("alert-danger").removeClass("hidden").html("There is an error with one or more of your settings");
@ -1806,6 +1969,7 @@ $(document).ready(function() {
$("#coinjs_multisig").val(o[2]);
$("#coinjs_hdpub").val(o[3]);
$("#coinjs_hdprv").val(o[4]);
$("#coinjs_derivation").val(o[7]);
// hide/show custom screen
if($("option:selected",this).val()=="custom"){
@ -1817,18 +1981,48 @@ $(document).ready(function() {
function configureBroadcast(){
var host = $("#coinjs_broadcast option:selected").val();
// api: blockcypher blockchair chain.so
// network name "btc" "bitcoin" "BTC"
// network name "ltc" "litecoin" "LTC"
// network name "doge" "dogecoin" "DOGE"
$("#rawSubmitBtn").unbind("");
if(host=="chain.so_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){
rawSubmitChainso_BitcoinMainnet(this);
rawSubmitChainso(this, "BTC");
});
} else if(host=="chain.so_litecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitchainso(this, "LTC");
});
} else if(host=="chain.so_dogecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitchainso_dogecoin(this);
rawSubmitchainso(this, "DOGE");
});
} else if(host=="blockcypher_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockcypher_BitcoinMainnet(this);
rawSubmitblockcypher(this, "btc");
});
} else if(host=="blockcypher_litecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockcypher(this, "ltc");
});
} else if(host=="blockcypher_dogecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockcypher(this, "doge");
});
} else if(host=="blockchair_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockchair(this, "bitcoin");
});
} else if(host=="blockchair_litecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockchair(this, "litecoin");
});
} else if(host=="blockchair_dogecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockchair(this, "dogecoin");
});
} else if(host=="cryptoid.info_carboncoin"){
$("#rawSubmitBtn").click(function(){

11
sha1sum
View File

@ -1,9 +1,9 @@
---- Version 1.4 2018.06.19 ---
---- Version 1.6 2020.10.02 ----
77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js
3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js
253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js
988f99187ab356bc5d12b61572f463e1785c15c2 ./js/coinbin.js
8b4163122d907f9c363b9afd8809490f5ba202c8 ./js/coin.js
cb5717166bf1c99abbd75a06013067c4a5897d5a ./js/coinbin.js
911fb7bdba24269029f27659e4040cd991b2307c ./js/coin.js
988565bc2cb402d63ed5c5fd7ff47c4278efc2c5 ./js/collapse.js
9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js
f7c09f2f5a721371e7d478050119f7e2d58e3ef9 ./js/crypto-sha256-hmac.js
@ -30,5 +30,6 @@ ca35b697d99cae4d1b60f2d60fcd37771987eb07 ./fonts/glyphicons-halflings-regular.w
de51a8494180a6db074af2dee2383f0a363c5b08 ./fonts/glyphicons-halflings-regular.svg
278e49a86e634da6f2a02f3b47dd9d2a8f26210f ./fonts/glyphicons-halflings-regular.woff
44bc1850f570972267b169ae18f1cb06b611ffa2 ./fonts/glyphicons-halflings-regular.ttf
c024021c71cba503979a859d23cbf7a88b570d82 ./README.md
26552aac02a06e88b419539f93032de8a25e1edd ./index.html
ee481606d8d48f402d152fa632ba9e5f9da7f169 ./README.md
a706e95f6436ee4a31dc26b17a9ac8ab1f0d3750 ./index.html
7130b64e3ef4cf6f2f1550e902f081c58dc053de ./test.html

379
test.html Normal file
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>