74 Commits

Author SHA1 Message Date
OutCast3k 2e0422656d removed blockr.io links as its closed down 2017-09-11 19:52:05 +00:00
OutCast3k 6c480a1102 segwit support added 2017-09-10 13:18:31 +00:00
OutCast3k d5fe5ea828 increase to default transaction fee (and donations) on the #wallet section, as well as links to bitcoinfees.21.co to assist with choosing a better transaction fee 2017-03-14 20:51:51 +00:00
OutCast3k 52b206c7d6 added a donation button to the #newTransaction page 2017-03-13 21:12:06 +00:00
OutCast3k 1f9d9e97c2 better sighash support for the gui, plus bug fixes and testing 2017-02-17 15:38:24 +00:00
OutCast3k d12b9d9072 final sighash tweak 2017-02-10 15:16:44 +00:00
OutCast3k 6c22adaa5a added extra sighash support for signing 2017-02-10 13:05:58 +00:00
OutCast3k 605a6df343 Updated coinbin.js
Fixed a bug, which was reported on https://www.reddit.com/r/Bitcoin/comments/5kowvt/psa_coinbin_appears_to_be_trying_to_steal_coins/ that appears to have caused incorrect HD key pairs to be generated in certain situations, because 'coinjs.compressed = true;' was not always being set when the user entered a HD onto the #verify tab.
2016-12-28 10:01:16 +00:00
OutCast3k 60efbb5174 updated sha1sum file due to recent edits 2016-12-28 09:54:06 +00:00
OutCast3k 1b111b335d updated coinbin.js
Fixed a bug, which was reported on https://www.reddit.com/r/Bitcoin/comments/5kowvt/psa_coinbin_appears_to_be_trying_to_steal_coins/ that appears to have caused incorrect HD key pairs to be generated in certain situations, because 'coinjs.compressed = true;' was not always being set when the user entered a HD onto the #verify tab.
2016-12-28 09:50:27 +00:00
OutCast3k 24028a001d Update sha1sum 2016-12-21 11:57:17 +00:00
OutCast3k f4c2b3d425 updated coinbin.js
fixed a small bug in the #wallet section of coinb.in
2016-12-21 11:56:18 +00:00
OutCast3k 20547ff133 Update sha1sum 2016-11-25 19:15:43 +00:00
OutCast3k 858774b640 fixed a bug introduced in previous commit 2016-09-13 03:36:49 +00:00
OutCast3k 21ecedaa48 added full carboncoin support 2016-09-11 18:40:18 +00:00
OutCast3k 3c1e957519 fixed a timelocked address bug as reported on issue 60 2016-09-06 07:06:36 +00:00
OutCast3k 44e6f5c639 update sha1sum 2016-09-05 13:32:05 +00:00
OutCast3k d176899774 dogecoin + chainso bugfix 2016-09-05 13:30:40 +00:00
OutCast3k 970cd756ec added better sighash support as well as (basic) support for carboncoin 2016-09-04 20:54:15 +00:00
OutCast3k b6dfa6b822 Merge pull request #59 from tomcarbon/master
Adding dogecoin support to coinb.in
2016-09-04 14:57:37 +01:00
Tom Carbon 85c9267379 Add files via upload 2016-09-03 22:20:09 -07:00
Tom Carbon 0c3530590f Add files via upload 2016-09-03 22:19:45 -07:00
OutCast3k 74a0fad4d2 Merge pull request #53 from DanielWeigl/master
Error in serialization for nLockTime values
2016-08-04 14:04:34 +01:00
OutCast3k 67f9c1f926 fixed a broadcasting issue 2016-07-28 23:40:31 +00:00
OutCast3k 67bd6e927c small bug fixes + enabled testnet via the #settings page 2016-07-28 22:36:27 +00:00
OutCast3k 284c6361e7 Merge pull request #54 from DanielWeigl/hodlheight
Allow HODL transaction to define nLockTime in blockheight or date/time
2016-07-28 22:56:03 +01:00
Daniel Weigl 347ccf4947 Allow HODL transaction to define nLockTime in blockheight or date/time
it still has a small UX quirks: the radio buttons dont get restored correctly after page reload
2016-07-03 19:34:59 +02:00
Daniel Weigl 8ac9f4207d Allow HODL transaction to define nLockTime in blockheight or date/time
it still has a small UX quirks: the radio buttons dont get restored correctly after page reload
2016-07-03 19:33:24 +02:00
Daniel Weigl 3ba79f0e3d Error in serialization for nLockTime values
if nLockTime is 1234(decimal) -> thats 4D2(hex) -> The current code splits it beginning from the end into bytes -> [4d, 02], but it should be [4, d2].

Error only occurs if one of the bytes is <16
2016-07-03 19:25:02 +02:00
OutCast3k cad1f6e98b update readme and sha1sum files 2016-06-08 22:27:13 +00:00
OutCast3k e818fc738d Merge pull request #51 from bip32JP/betterFeeWarn
Added fluid fee to catch smaller mistakes as well.
2016-06-08 23:23:09 +01:00
bip32JP 0a94fb64ef Added fluid fee to catch smaller mistakes as well. 2016-05-26 21:32:52 +09:00
OutCast3k e3fff74690 coinb.in now supports replace by fee (RBF) transactions 2016-05-21 15:47:10 +00:00
OutCast3k 0154514309 bug fix to blockcyphers broadcasting option, plus added a buy bitcoin button on the wallet page 2016-05-09 10:02:51 +00:00
OutCast3k 1e8773c195 added blockcypher.com to list of broadcast providers 2016-03-21 13:34:19 +00:00
OutCast3k 1ea47f6ff5 this commit makes it obvious as to how to add new providers (although this could change soon) more providers to be added in the next commit. 2016-03-15 23:47:40 +00:00
OutCast3k b943cbd6de add missing date and time placeholder from the time locked address page 2016-03-03 13:23:36 +00:00
OutCast3k 53c48af90c bug fix 2016-02-26 19:05:45 +00:00
OutCast3k 6970a07d60 bug fixes, credit to ibblondon and nxtchg. thanks 2016-02-25 23:09:43 +00:00
OutCast3k 695947b02d updated the #wallet section of the site so that when a transaction fails to broadcast due to a server side error it displays it in a box that can be manually processed elsewhere 2016-02-09 23:52:55 +00:00
OutCast3k 0a8bb6f33a update sha1sum 2016-02-09 23:29:29 +00:00
OutCast3k 27c9bff17e add extra validation to prevent invalid public keys being used. (as per issue 39) 2016-02-09 23:27:34 +00:00
OutCast3k c276998687 increased default fee on #wallet section of coinb.in 2015-12-30 00:17:36 +00:00
OutCast3k 4f16149a26 updated sha1sum file 2015-12-29 20:11:49 +00:00
OutCast3k 7bfacd51b1 fixed a small interface issue with the input feilds on the verify tab for hodl addresses 2015-12-29 20:06:03 +00:00
OutCast3k 1da38e46f7 small interface bugfix 2015-12-29 16:36:27 +00:00
OutCast3k 133a5d2858 few minor gui changes to the "New Time Locked Address" section 2015-12-29 16:20:53 +00:00
OutCast3k a9cfa44c44 Merge pull request #37 from thelink2012/test-time
Simple Hodl Address
2015-12-29 14:27:09 +00:00
Denilson M. Amorim cedc6dddaf Fix endianess of checklocktimeverify 2015-12-29 00:00:11 -03:00
Denilson M. Amorim d53c236ec3 Set #nLockTime automatically 2015-12-27 01:15:47 -03:00
Denilson M. Amorim c8577e03be Simple Hodl Address 2015-12-27 00:37:51 -03:00
OutCast3k 9a669885b3 Merge pull request #32 from itscory/patch-1
fixed issue with copying the script URL
2015-11-16 13:21:37 +00:00
itscory 8652fe789d made copying the scriptUrl easier
I noticed, at least on Firefox, that it is impossible to highlight and copy the script URL. I fixed this by changing the "disabled" attribute to "readonly."
2015-11-15 13:35:53 -05:00
OutCast3k 6b39b86447 updated the #broadcast page to use jquerys POST request over the GET request that was being used to handle larger transactions 2015-09-16 11:41:18 +00:00
OutCast3k 902370679f update sha1sum and readme 2015-09-12 19:17:21 +00:00
OutCast3k ab395a82f2 lots of of small changes; bug fixes, extra validation, warning of large fee, a mediation section and more 2015-09-12 18:38:34 +00:00
OutCast3k fe141b0b8a removed the mention of google analytics from the about page as its no longer being used 2015-08-31 12:20:36 +01:00
OutCast3k e33b2dc58e Merge pull request #25 from dabura667/findunconf
Fetch unconfirmed utxos as well
2015-08-31 11:45:21 +01:00
dabura667 a62a822b71 Fetch unconfirmed utxos as well 2015-08-30 10:51:42 +09:00
OutCast3k 91ee89282f Merge pull request #23 from dasource/master
Add ShadowCash
2015-08-17 12:08:28 +01:00
dasource 42391aba8e Add ShadowCash 2015-08-16 22:34:40 +01:00
OutCast3k 8e0742d64c minor bug fix from previous commit 2015-08-14 22:09:51 +00:00
OutCast3k a1c3c60244 added extra support for altcoins, litecoin beta added via #settings page 2015-08-14 21:07:19 +00:00
OutCast3k 004de1f318 added localbitcoins.com trading link to the about page 2015-07-27 18:13:09 +00:00
OutCast3k 6f8cd22d5f increased the amount of bytes allowed when using op_return from 40 to 80 2015-07-27 18:04:41 +00:00
OutCast3k cacc30cc95 update sha1sum file 2015-07-27 18:00:30 +00:00
OutCast3k d2f1d3a5d5 fixed a typo (thanks for pointing that out Injust) 2015-07-27 17:58:13 +00:00
OutCast3k 1c3e81bfd2 update coinbin.js as it wasn't allowing multisig addresses to be added to new transactions 2015-07-03 18:47:58 +01:00
OutCast3k cf71efcf59 Merge pull request #15 from bulldozer2003/master
display base58 address for redeem script
2015-06-29 07:29:41 +01:00
OutCast3k 92de202ed0 update sha1sum file 2015-06-23 23:15:57 +00:00
OutCast3k 6e821cf53a fixed a bug with the settings page 2015-06-23 23:12:09 +00:00
OutCast3k 85ec366c6e corrected testnet address prefix 2015-06-23 23:05:28 +00:00
OutCast3k 717f5cc7ef corrected donation address 2015-06-23 23:00:10 +00:00
bulldozer2003 da2d20f477 display base58 address in addition to public key when decoding redeem script 2015-06-19 12:15:46 -05:00
11 changed files with 1745 additions and 241 deletions
+4 -1
View File
@@ -1,7 +1,7 @@
coinbin
=======
A Open Source Browser Based Bitcoin Wallet. Version 1.2 beta by OutCast3k
A Open Source Browser Based Bitcoin Wallet. Version 1.3 beta by OutCast3k
Live version available at http://coinb.in/ or http://4zpinp6gdkjfplhk.onion
@@ -26,5 +26,8 @@ Coinb.in supports a number of key features such as:
- 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
Donate to 1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg to see more development!
File diff suppressed because one or more lines are too long
+8
View File
@@ -24,3 +24,11 @@ body {
background-color: #f5f5f5;
padding-top: 20px;
}
.alert {
overflow: hidden;
-ms-text-overflow: ellipsis;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
display: block;
}
+363 -21
View File
@@ -12,10 +12,16 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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>
@@ -52,8 +58,10 @@
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-plus"></span> New<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#newAddress" data-toggle="tab">New Address</a></li>
<li><a href="#newAddress" data-toggle="tab">Address</a></li>
<li><a href="#newSegWit" data-toggle="tab">SegWit Address</a></li>
<li><a href="#newMultiSig" data-toggle="tab">MultiSig Address</a></li>
<li><a href="#newTimeLocked" data-toggle="tab">Time Locked Address</a></li>
<li><a href="#newHDaddress" data-toggle="tab">HD Address</a></li>
<li class="divider"></li>
<li><a href="#newTransaction" data-toggle="tab">Transaction</a></li>
@@ -94,7 +102,7 @@
<div class="row">
<div class="col-md-4">
<h3><span class="glyphicon glyphicon-ok"></span> Open Source</h3>
<p>Coinbin is an open source web based wallet written in javascript and released under the <a href="LICENSE">MIT license</a> which means its free to use and edit.</p>
<p>Coinbin is an open source web based wallet written in javascript and released under the <a href="LICENSE">MIT license</a> which means it's free to use and edit.</p>
</div>
<div class="col-md-4">
@@ -116,7 +124,7 @@
<div class="col-md-4">
<h3><span class="glyphicon glyphicon-globe"></span> Addresses</h3>
<p>We support <a href="#newAddress">regular addresses</a> but also <a href="#newMultiSig">multisig</a> and stealth, and access to your own private keys!</p>
<p>We support <a href="#newAddress">regular addresses</a>, <a href="#newMultiSig">multisig</a>, <a href="#newSegWit">segwit</a> and stealth all with access to your own private keys!</p>
</div>
<div class="col-md-4">
@@ -165,6 +173,7 @@
<li role="presentation" class="active"><a href="javascript:;" id="walletBalance">0.00 BTC</a></li>
<li role="presentation"><a href="javascript:;" id="walletShowSpend">Spend</a></li>
<li role="presentation"><a id="walletHistory" href="javascript:;" target="_blank">History</a></li>
<li role="presentation"><a href="https://localbitcoins.com/?ch=173j" target="_blank">Buy</a></li>
<li role="presentation"><a href="javascript:;" id="walletShowKeys">Keys</a></li>
</ul>
@@ -214,12 +223,12 @@
</div>
<div class="row">
<div class="col-xs-6">
<label><abbr title="the amount to pay in network miner fees - 0.0001 or more recommended">Transaction Fee</abbr></label>
<input type="text" class="form-control" value="0.00001" id="txFee">
<label><abbr title="the amount to pay in network miner fees - 0.0004 or more recommended for a faster processing time">Transaction Fee</abbr>&nbsp;&nbsp;<a href="https://bitcoinfees.21.co/" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></label>
<input type="text" class="form-control" value="0.0004" id="txFee">
</div>
<div class="col-xs-5">
<label><abbr title="the amount to donate to the sites developer">Donation</abbr></label>
<input type="text" class="form-control" value="0.00" id="developerDonation">
<label><abbr title="the amount to donate to coinb.in">Donation</abbr></label>
<input type="text" class="form-control" value="0.003" id="developerDonation">
</div>
</div>
<br>
@@ -298,11 +307,64 @@
<br>
</div>
<div class="tab-pane tab-content" id="newSegWit">
<h2>New SegWit Address <small> Smaller &amp; Faster Transactions</small></h2>
<p>Any keys used you will need to manually store safely as they will be needed later to redeem the bitcoins.</p>
<label>SegWit Address (Share)</label>
<div class="input-group">
<input id="newSegWitAddress" type="text" class="form-control address" value="" readonly>
<span class="input-group-btn">
<button class="qrcodeBtn btn btn-default" type="button" data-toggle="modal" data-target="#modalQrcode"><span class="glyphicon glyphicon-qrcode"></span></button>
</span>
</div>
<label>RedeemScript</label>
<input id="newSegWitRedeemScript" type="text" class="form-control" readonly>
<label>Public key</label>
<input id="newSegWitPubKey" type="text" class="form-control" readonly>
<label>Private key (WIF key)</label>
<div class="input-group">
<input id="newSegWitPrivKey" type="password" class="form-control" value="" readonly>
<span class="input-group-btn">
<button class="showKey btn btn-default" type="button">Show</button>
</span>
</div>
<h3>Address Options</h3>
<p>You can use the advanced options below to generate different kind of keys and addresses.</p>
<div class="checkbox">
<label><input type="checkbox" id="newSegWitBrainwallet" class="checkbox-inline"> Custom Seed or Brain Wallet</label>
<input type="text" class="form-control hidden" id="brainwalletSegWit">
</div>
<input type="button" class="btn btn-primary" value="Generate" id="newSegWitKeysBtn">
<br>
</div>
<div class="tab-pane tab-content" id="newMultiSig">
<h2>New Multisig Address <small>Secure multisig address</small></h2>
<div class="row">
<div class="col-md-8">
<p>Public keys can be <a href="#newAddress">generated in your browser</a> or from your bitcoin client</a>.</p>
<p>Enter the public keys of all the participants, to create a <a href="https://en.bitcoin.it/wiki/Address#Multi-signature_addresses" target="_blank">multi signature address</a>. Maximum of 15 allowed. Compressed and uncompressed public keys are accepted.</p>
</div>
<div class="col-md-3">
<p class="alert alert-info"><span class="glyphicon glyphicon-info-sign"></span> <a href="javascript:;" data-toggle="modal" data-target="#modalMediator"><abbr>Need a Mediator?</abbr></a></p>
</div>
<div class="col-md-1">
</div>
</div>
<div id="multisigPubKeys" class="row">
<div class="form-horizontal">
@@ -358,13 +420,90 @@
<p>This script should be <i>saved and should be shared with all the participants before a payment is made</i>, so they may validate the authenticity of the address, it will also be used later to release the bitcoins.</p>
<textarea class="form-control script" style="height:160px" readonly></textarea>
<label>Shareable URL</label>
<input type="text" class="scriptUrl form-control" disabled>
<input type="text" class="scriptUrl form-control" readonly>
</div>
<input type="button" class="btn btn-primary" value="Submit" id="newMultiSigAddress">
<br>
</div>
<div class="tab-pane tab-content" id="newTimeLocked">
<h2>New Time Locked Address <small>Coins can be released only after a certain date</small></h2>
<div class="row">
<div class="col-md-11">
<p>Use <i><a href="https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki" target="_blank">OP_CHECKLOCKTIMEVERIFY</a></i> (OP_HODL) to create a time locked address where the funds are unspendable until a set date and time has passed.</p>
<p>Public keys can be <a href="#newAddress">generated in your browser</a> or from your bitcoin client</a>.</p>
<p>Enter the public key that will be able to unlock the funds after the a certain date.
</div>
<div class="col-md-1">
</div>
</div>
<div class="row">
<div class="form-horizontal">
<div class="col-xs-12">
<input id="timeLockedPubKey" type="text" class="form-control pubkey">
</div>
</div>
</div>
<p id="timeLockedRbTypeBox">
Enter the
<input type="radio" id="timeLockedRbTypeDate" name="timeLockedRbType" value="date" checked="checked">
<label for="timeLockedRbTypeDate">date and time</label>
or
<input type="radio" id="timeLockedRbTypeBlockHeight" name="timeLockedRbType" value="blockheight">
<label for="timeLockedRbTypeBlockHeight">blockheight</label>
required to release the coins:
</p>
<div class="row">
<div class='col-md-6'>
<div class="form-group">
<div class='input-group date' id='timeLockedDateTimePicker'>
<input type='text' class="form-control" placeholder="MM/DD/YYYY hh:mm" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
<div class='input-group hidden' id='timeLockedBlockHeight'>
<input type='text' id='timeLockedBlockHeightVal' class="form-control" placeholder="Blockheight" />
</div>
</div>
</div>
</div>
<br>
<div id="timeLockedErrorMsg" class="alert alert-danger" style="display:none;"></div>
<div class="alert alert-success hidden" id="timeLockedData">
<label>Address</label>
<p>Payment should be made to this address:</p>
<div class="row">
<div class="col-lg-6">
<div class="input-group">
<input type="text" class="form-control address" value="" readonly>
<span class="input-group-btn">
<button class="qrcodeBtn btn btn-default" type="button" data-toggle="modal" data-target="#modalQrcode"><span class="glyphicon glyphicon-qrcode"></span></button>
</span>
</div>
</div>
</div>
<label>Redeem Script</label>
<p>This script should be <i>saved and should be shared with all the participants before a payment is made</i>, so they may validate the authenticity of the address, it will also be used later to release the bitcoins.</p>
<textarea class="form-control script" style="height:160px" readonly></textarea>
<label>Shareable URL</label>
<input type="text" class="scriptUrl form-control" readonly>
</div>
<input type="button" class="btn btn-primary" value="Submit" id="newTimeLockedAddress">
<br>
</div>
<div class="tab-pane tab-content" id="newHDaddress">
<h2>New HD Address <small>making bip32 even easier</small></h2>
<p>Use the form below to generate a <i>master</i> hierarchical deterministic address.</p>
@@ -400,7 +539,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 Multisig Redeem Script</b>:
<b>Address, WIF key or Redeem Script</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>
@@ -429,7 +568,7 @@
<hr>
<label>Null Data</label> <span class="text-muted text-normal">(40 byte limit)</span>
<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>
<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>
@@ -442,6 +581,19 @@
<input type="text" class="form-control" value="0" id="nLockTime">
<hr>
<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>
</p>
<hr>
<label>Network</label>
<p>The <a href="#settings">settings</a> page can be used to select alternative networks of which you can retrieve your unspent outputs and broadcast a signed transaction into.</p>
<hr>
</div>
</div>
@@ -453,7 +605,11 @@
<br>
<div class="tab-content">
<div class="tab-pane fade in active" id="txoutputs">
<span class="pull-right"><a href="javascript:;" id="donateTxBtn" class="btn btn-link"><span class="glyphicon glyphicon-heart"></span> Donate!</a></span>
<p>Enter the address and amount you wish to make a payment to.</p>
<div class="row">
<div class="col-xs-8">
@@ -529,13 +685,15 @@
<div class="row">
<div class="col-xs-3">
<label><abbr title="What is not spent will be used as a transaction fee">Transaction Fee</abbr></label>
<label><abbr title="What is not spent will be used as a transaction fee">Transaction Fee</abbr>&nbsp;&nbsp;<a href="https://bitcoinfees.21.co/" target="_blank"><span class="glyphicon glyphicon-question-sign"></span></a></label>
<input type="text" id="transactionFee" class="form-control" value="0.0000" readonly>
</div>
</div>
<br>
<div id="transactionCreateStatus" class="alert alert-danger hidden"></div>
<div id="transactionCreate" class="alert alert-success hidden">
<label>Transaction</label>
<button class="qrcodeBtn btn btn-default" type="button" data-toggle="modal" data-target="#modalQrcode" style="float:right;"><span class="glyphicon glyphicon-qrcode"></span></button>
@@ -563,8 +721,11 @@
<br>
<div class="hidden verifyData" id="verifyRsData">
<h4>Redeem Script</h4>
<p><span style="float:right"><a href="javascript:;" target="_blank" class="verifyLink" title="Link to this page"><span class="glyphicon glyphicon-link"></span></a></span>The above redeem script has been decoded</p>
<div class="hidden" id="verifyRsDataMultisig">
<label>Multi Signature Address</label>
<div class="row">
<div class="col-lg-6">
@@ -576,6 +737,7 @@
</div>
</div>
</div>
<label>Required Signatures</label>
<p class="signaturesRequired">?</p>
<label>Signatures Required from</label>
@@ -583,6 +745,58 @@
<tbody>
</tbody>
</table>
<br>
</div>
<div class="hidden verifyData" id="verifyRsDataSegWit">
<label>Segwit Address</label>
<div class="row">
<div class="col-lg-6">
<div class="input-group">
<input type="text" class="form-control address segWitAddress" value="" readonly>
<span class="input-group-btn">
<button class="qrcodeBtn btn btn-default" type="button" data-toggle="modal" data-target="#modalQrcode"><span class="glyphicon glyphicon-qrcode"></span></button>
</span>
</div>
</div>
</div>
<br>
</div>
<div class="hidden verifyData" id="verifyRsDataHodl">
<label>Hodl Address</label>
<div class="row">
<div class="col-md-12">
<div class="input-group">
<input type="text" class="form-control address" value="" readonly>
<span class="input-group-btn">
<button class="qrcodeBtn btn btn-default" type="button" data-toggle="modal" data-target="#modalQrcode"><span class="glyphicon glyphicon-qrcode"></span></button>
</span>
</div>
</div>
</div>
<label>Required Signature</label>
<div class="row">
<div class="col-md-12">
<div class="input-group">
<input type="text" class="form-control address pubkey" value="" readonly>
<span class="input-group-btn">
<button class="qrcodeBtn btn btn-default" type="button" data-toggle="modal" data-target="#modalQrcode"><span class="glyphicon glyphicon-qrcode"></span></button>
</span>
</div>
</div>
</div>
<label>Unlock Time</label>
<div class="row">
<div class='col-md-4'>
<div class="input-group">
<input type="text" class="form-control date" value="" readonly>
</div>
</div>
</div>
</div>
</div>
<div class="hidden verifyData" id="verifyTransactionData">
@@ -591,6 +805,8 @@
<div><b>Version</b>: <span class="transactionVersion"></span></div>
<div><b>Transaction Size</b>: <span class="transactionSize"></span></div>
<div><b>Lock time</b>: <span class="transactionLockTime"></span></div>
<div class="transactionSegWit"><b>SegWit</b>: True</div>
<div class="transactionRBF"><b>RBF</b>: This is a <a href="https://en.bitcoin.it/wiki/Transaction_replacement">replace by fee</a> transaction!</div>
<hr>
@@ -617,6 +833,7 @@
</table>
</div>
<div class="hidden verifyData" id="verifyPrivKey">
<h4>WIF key</h4>
<p>The above wif key has been decoded</p>
@@ -726,11 +943,13 @@
<input type="button" value="Submit" class="btn btn-primary" id="verifyBtn">
<br>
</div>
<div class="tab-pane tab-content" id="sign">
<h2>Sign Transaction <small>once a transaction has been verified</small></h2>
<p>Once you have <a href="#verify">verified</a> a transaction you can sign and then <a href="#broadcast">broadcast</a> it into the network.</p>
<div class="row">
<div class="col-md-12">
<label for="signPrivateKey">Private key</label>
@@ -752,6 +971,33 @@
</div>
<br>
<a href="javascript:;" id="signAdvancedCollapse">
<div class="well well-sm"><span class="glyphicon glyphicon-collapse-down"></span> Advanced Options</div>
</a>
<div id="signAdvanced" class="hidden">
<div class="row">
<div class="col-md-12">
<label for="sighashType">Sig Hash Type</label>
<select id="sighashType" class="form-control">
<option value="1" rel="SIGHASH_ALL: Signs all the inputs and outputs, protecting everything against modification.">ALL (default)</option>
<option value="2" rel="SIGHASH_NONE: Signs all of the inputs but none of the outputs, allowing anyone to change where the satoshis are going unless other signatures using other signature hash flags protect the outputs.">NONE</option>
<option value="3" rel="SIGHASH_SINGLE: The only output signed is the one corresponding to this input, ensuring nobody can change your part of the transaction but allowing other signers to change their part of the transaction.">SINGLE</option>
<option value="129" rel="SIGHASH_ALL|SIGHASH_ANYONECANPAY: Signs all of the outputs but only this one input, it allows anyone to add or remove other inputs, so anyone can contribute additional satoshis but they cannot change how many satoshis are sent nor where they go.">ALL|ANYONECANPAY</option>
<option value="130" rel="SIGHASH_NONE|SIGHASH_ANYONECANPAY: Signs only this one input and allows anyone to add or remove other inputs or outputs, so anyone who gets a copy of this input can spend it however they'd like.">NONE|ANYONECANPAY</option>
<option value="131" rel="SIGHASH_SINGLE|SIGHASH_ANYONECANPAY: Signs this one input and its corresponding output. Allows anyone to add or remove other inputs.">SINGLE|ANYONECANPAY</option>
</select>
</div>
</div>
<br>
<div class="alert alert-info" id="sighashTypeInfo">
SIGHASH_ALL: The default, signs all the inputs and outputs, protecting everything except the signature scripts against modification.
</div>
</div>
<div class="alert alert-danger hidden" id="signedDataError">
<span class="glyphicon glyphicon-exclamation-sign"></span> There is a problem with one or more of your inputs, please check and try again
</div>
@@ -772,6 +1018,7 @@
<div class="tab-pane tab-content" id="broadcast">
<h2>Broadcast Transaction <small>into the bitcoin network</small></h2>
<a href="#settings" style="float:right;"><span class="glyphicon glyphicon-cog"></span></a>
<p>Enter your hex encoded bitcoin transaction</p>
<textarea class="form-control" style="height:125px" id="rawTransaction"></textarea>
<br>
@@ -789,19 +1036,22 @@
<div class="tab-pane tab-content" id="about">
<h2>About <small>open source bitcoin wallet</small></h2>
<p>Version 1.2</p>
<p>Version 1.3</p>
<p>Compatible with bitcoin-qt</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>
<h3>What is bitcoin?</h3>
<h3>What is Bitcoin?</h3>
<p>Bitcoin is a type of digital currency in which encryption techniques are used to regulate the generation of units of currency and verify the transfer of funds, operating independently of a central bank. See <a href="http://www.weusecoins.com/" target="_blank">weusecoins.com</a> for more information.</p>
<p>If you are looking to buy some Bitcoin try <a href="https://localbitcoins.com/?ch=173j" target="_blank">LocalBitcoins.com</a>.</p>
<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>
<h3>Privacy</h3>
<p>Coinb.in beleives 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 use google analytics to track hits and route traffic via cloudflare using an SSL certificate.</p>
<p>Coinb.in beleives 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, 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:1CWHWkTWaq1K5hevimJia3cy">1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg</a> if you found this project useful or want to see more features!</p>
<p>Please donate to <a href="bitcoin:1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg">1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg</a> if you found this project useful or want to see more features!</p>
</div>
<div class="tab-pane tab-content" id="settings">
@@ -814,7 +1064,10 @@
<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="bitcoin_testnet" rel="0x6f;0xc4;0xef;0x043587cf;0x04358394;blockr.io_bitcointestnet;false">Bitcoin (testnet)</option>
<option value="dogecoin_mainnet" rel="0x1e;0x9e;0x16;0x0827421e;0x089944e4;chain.so_dogecoin;chain.so_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>
<option value="custom" rel="0x00;0x80;0x05;0x488b21e;0x488ade4;false;false">Custom</option>
</select>
@@ -857,7 +1110,7 @@
<br>
<div class="alert alert-info"> <span class="glyphicon glyphicon-info-sign"></span> You will not be able to automatically broadcast or retreive your unspent inputs from coinb.in when using this setting and will need to use your desktop client instead, however everything else will continue to function normally.</div>
<div class="alert alert-info"> <span class="glyphicon glyphicon-info-sign"></span> You will not be able to automatically broadcast or retreive your unspent outputs from coinb.in when using this setting and will need to use your desktop client instead, however everything else such as creating key pairs, addresses, transaction generation and signing will continue to function normally.</div>
</div>
<hr>
@@ -868,8 +1121,10 @@
<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="blockr.io_bitcoinmainnet"> Blockr.io (Bitcoin mainnet)</option>
<option value="blockr.io_bitcointestnet"> Blockr.io (Bitcoin testnet)</option>
<option value="chain.so_bitcoinmainnet"> Chain.so (Bitcoin mainnet)</option>
<option value="blockcypher_bitcoinmainnet"> Blockcypher.com (Bitcoin mainnet)</option>
<option value="chain.so_dogecoin"> Chain.so (Dogecoin)</option>
<option value="cryptoid.info_carboncoin"> Cryptoid.info (Carboncoin)</option>
</select>
</div>
</div>
@@ -882,6 +1137,9 @@
<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="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>
</div>
</div>
@@ -896,7 +1154,7 @@
</div>
<br>
<p class="text-muted">This page uses javascript to generate your addresses and sign your transactions within your browser, this means we <i>never</i> receive your private keys, this can be indepently verified by reviewing the source code on <a href="https://github.com/OutCast3k/coinbin/" target="_blank">github</a>. You can even <a href="https://github.com/OutCast3k/coinbin/archive/master.zip">download</a> this page and host it yourself or run it offline!</p>
<p class="text-muted">This page uses javascript to generate your addresses and sign your transactions within your browser, this means we <i>never</i> receive your private keys, this can be independently verified by reviewing the source code on <a href="https://github.com/OutCast3k/coinbin/" target="_blank">github</a>. You can even <a href="https://github.com/OutCast3k/coinbin/archive/master.zip">download</a> this page and host it yourself or run it offline!</p>
<br>
</div>
@@ -905,7 +1163,7 @@
<div id="footer">
<div class="container text-right">
<p class="text-muted">Version 1.2</p>
<p class="text-muted">Version 1.3</p>
</div>
</div>
@@ -924,6 +1182,12 @@
<br>
<div id="walletSendConfirmStatus" class="alert alert-danger hidden"></div>
<div id="walletSendFailTransaction" class="alert alert-info hidden">
<b>Raw Transaction:</b>
<p>Below is a copy of the transaction we tried to submit</p>
<textarea class="form-control" readonly></textarea>
</div>
</div>
<div class="modal-footer">
@@ -980,6 +1244,84 @@
</div>
<!-- qrcode scanner modal -->
<!-- mediator modal -->
<div class="modal fade" id="modalMediator" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Transaction Mediation</h4>
</div>
<div class="modal-body">
<p>You can add a public key when creating a <i>2-of-3 multi signature address</i> and for a low fee your mediator will help with the recovery of the funds should any disputes arise.</p>
<p>Should a dispute arise please contact the below address for further information</p>
<div class="row">
<div class="col-md-5">
<label>Mediator:</label>
<!--
You need to contact us before adding your pubkey
and submitting a pull request on github.
format is: pubkey;email;fee
-->
<select id="mediatorList" class="form-control">
<option value="02b6231cc602740c29436eafbb6448880f4058cc3d2745c709deee313104678277;support@coinb.in;1">Coinb.in</option>
</select>
</div>
<div class="col-md-5">
<label>Address:</label> <span class="text-muted">(for disputes)</span>
<input id="mediatorEmail" type="text" class="form-control address" value="" readonly>
</div>
<div class="col-md-2">
<label>Fee (%):</label>
<input id="mediatorFee" type="text" class="form-control address" value="" readonly>
</div>
</div>
<br>
<label>Public Key:</label>
<input id="mediatorPubkey" type="text" class="form-control address" value="" readonly>
<br>
</div>
<div class="modal-footer">
<button class="btn btn-primary" type="button" id="mediatorAddKey">Add Public Key</button>
<button type="button" class="btn btn-default" data-dismiss="modal" id="mediatorClose">Close</button>
</div>
</div>
</div>
</div>
<!-- mediator modal -->
<!-- warning (fee) modal -->
<div class="modal fade" id="modalWarningFee" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title"><b>Warning High Fee!</b></h4>
</div>
<div class="modal-body">
Please be aware that you have created a transaction with what seems to be a very high fee of <span id="modalWarningFeeAmount"></span> BTC!
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal" id="warningFeeClose">OK, I've got it!</button>
</div>
</div>
</div>
</div>
<!-- warning (fee) modal -->
<div class="hidden" id="entropybucket"></div>
</body>
</html>
File diff suppressed because one or more lines are too long
+379 -42
View File
@@ -1,6 +1,6 @@
/*
Coinjs 0.01 beta by OutCast3k{at}gmail.com
A bitcoin frameworkcoinjs.
A bitcoin framework.
http://github.com/OutCast3k/coinjs or http://coinb.in/coinjs
*/
@@ -98,9 +98,9 @@
}
/* provide a public key and return address */
coinjs.pubkey2address = function(h){
coinjs.pubkey2address = function(h, byte){
var r = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(h), {asBytes: true}));
r.unshift(coinjs.pub);
r.unshift(byte || coinjs.pub);
var hash = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
var checksum = hash.slice(0, 4);
return coinjs.base58encode(r.concat(checksum));
@@ -135,6 +135,49 @@
return {'address':address, 'redeemScript':redeemScript};
}
/* new time locked address, provide the pubkey and time necessary to unlock the funds.
when time is greater than 500000000, it should be a unix timestamp (seconds since epoch),
otherwise it should be the block height required before this transaction can be released.
may throw a string on failure!
*/
coinjs.simpleHodlAddress = function(pubkey, checklocktimeverify) {
if(checklocktimeverify < 0) {
throw "Parameter for OP_CHECKLOCKTIMEVERIFY is negative.";
}
var s = coinjs.script();
s.writeBytes(coinjs.numToByteArray(checklocktimeverify));
s.writeOp(177);//OP_CHECKLOCKTIMEVERIFY
s.writeOp(117);//OP_DROP
s.writeBytes(Crypto.util.hexToBytes(pubkey));
s.writeOp(172);//OP_CHECKSIG
var x = ripemd160(Crypto.SHA256(s.buffer, {asBytes: true}), {asBytes: true});
x.unshift(coinjs.multisig);
var r = x;
r = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
var checksum = r.slice(0,4);
var redeemScript = Crypto.util.bytesToHex(s.buffer);
var address = coinjs.base58encode(x.concat(checksum));
return {'address':address, 'redeemScript':redeemScript};
}
/* create a new segwit address */
coinjs.segwitAddress = function(pubkey){
var keyhash = [0x00,0x14].concat(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubkey), {asBytes: true}), {asBytes: true}));
var x = ripemd160(Crypto.SHA256(keyhash, {asBytes: true}), {asBytes: true});
x.unshift(coinjs.multisig);
var r = x;
r = Crypto.SHA256(Crypto.SHA256(r, {asBytes: true}), {asBytes: true});
var checksum = r.slice(0,4);
var address = coinjs.base58encode(x.concat(checksum));
return {'address':address, 'type':'segwit', 'redeemscript':Crypto.util.bytesToHex(keyhash)};
}
/* provide a privkey and return an WIF */
coinjs.privkey2wif = function(h){
var r = Crypto.util.hexToBytes(h);
@@ -248,6 +291,7 @@
/* decompress an compressed public key */
coinjs.pubkeydecompress = function(pubkey) {
if((typeof(pubkey) == 'string') && pubkey.match(/^[a-f0-9]+$/i)){
var curve = EllipticCurve.getSECCurveByName("secp256k1");
try {
var pt = curve.curve.decodePointHex(pubkey);
@@ -263,6 +307,8 @@
return false;
}
}
return false;
}
coinjs.testdeterministicK = function() {
// https://github.com/bitpay/bitcore/blob/9a5193d8e94b0bd5b8e7f00038e7c0b935405a03/test/crypto/ecdsa.js
@@ -587,7 +633,7 @@
} else if (coinjs.isArray(data)) {
r.buffer = data;
} else if (data instanceof coinjs.script) {
r.buffer = r.buffer;
r.buffer = data.buffer;
} else {
r.buffer = data;
}
@@ -649,6 +695,21 @@
r.pubkeys = pubkeys;
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"
} else if((s.chunks.length==2) && (s.buffer[0] == 0 && s.buffer[1] == 20)){ // SEGWIT
r = {};
r.type = "segwit__";
var rs = Crypto.util.bytesToHex(s.buffer);
r.address = coinjs.pubkey2address(rs, coinjs.multisig);
r.redeemscript = rs;
} else if(s.chunks.length == 5 && s.chunks[1] == 177 && s.chunks[2] == 117 && s.chunks[4] == 172){
// ^ <unlocktime> OP_CHECKLOCKTIMEVERIFY OP_DROP <pubkey> OP_CHECKSIG ^
r = {}
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;
r.type = "hodl__";
}
} catch(e) {
// console.log(e);
@@ -661,7 +722,7 @@
r.spendToScript = function(address){
var addr = coinjs.addressDecode(address);
var s = coinjs.script();
if(addr.version==5){ // multisig address
if(addr.version==coinjs.multisig){ // multisig address
s.writeOp(169); //OP_HASH160
s.writeBytes(addr.bytes);
s.writeOp(135); //OP_EQUAL
@@ -731,15 +792,16 @@
r.lock_time = 0;
r.ins = [];
r.outs = [];
r.witness = [];
r.timestamp = null;
r.block = null;
/* add an input to a transaction */
r.addinput = function(txid, index, script){
r.addinput = function(txid, index, script, sequence){
var o = {};
o.outpoint = {'hash':txid, 'index':index};
o.script = coinjs.script(script||[]);
o.sequence = (r.lock_time==0) ? 4294967295 : 0;
o.sequence = sequence || ((r.lock_time==0) ? 4294967295 : 0);
return this.ins.push(o);
}
@@ -796,7 +858,7 @@
/* add data to a transaction */
r.adddata = function(data){
var r = false;
if(((data.match(/^[a-f0-9]+$/gi)) && data.length<80) && (data.length%2)==0) {
if(((data.match(/^[a-f0-9]+$/gi)) && data.length<160) && (data.length%2)==0) {
var s = coinjs.script();
s.writeOp(106); // OP_RETURN
s.writeBytes(Crypto.util.hexToBytes(data));
@@ -870,9 +932,12 @@
}
/* generate the transaction hash to sign from a transaction input */
r.transactionHash = function(index) {
r.transactionHash = function(index, sigHashType) {
var clone = coinjs.clone(this);
if((clone.ins) && clone.ins[index]){
var shType = sigHashType || 1;
/* black out all other ins, except this one */
for (var i = 0; i < clone.ins.length; i++) {
if(index!=i){
clone.ins[i].script = coinjs.script();
@@ -882,8 +947,62 @@
var extract = this.extractScriptKey(index);
clone.ins[index].script = coinjs.script(extract['script']);
if((clone.ins) && clone.ins[index]){
/* SIGHASH : For more info on sig hashs see https://en.bitcoin.it/wiki/OP_CHECKSIG
and https://bitcoin.org/en/developer-guide#signature-hash-type */
if(shType == 1){
//SIGHASH_ALL 0x01
} else if(shType == 2){
//SIGHASH_NONE 0x02
clone.outs = [];
for (var i = 0; i < clone.ins.length; i++) {
if(index!=i){
clone.ins[i].sequence = 0;
}
}
} else if(shType == 3){
//SIGHASH_SINGLE 0x03
clone.outs.length = index + 1;
for(var i = 0; i < index; i++){
clone.outs[i].value = -1;
clone.outs[i].script.buffer = [];
}
for (var i = 0; i < clone.ins.length; i++) {
if(index!=i){
clone.ins[i].sequence = 0;
}
}
} else if (shType >= 128){
//SIGHASH_ANYONECANPAY 0x80
clone.ins = [clone.ins[index]];
if(shType==129){
// SIGHASH_ALL + SIGHASH_ANYONECANPAY
} else if(shType==130){
// SIGHASH_NONE + SIGHASH_ANYONECANPAY
clone.outs = [];
} else if(shType==131){
// SIGHASH_SINGLE + SIGHASH_ANYONECANPAY
clone.outs.length = index + 1;
for(var i = 0; i < index; i++){
clone.outs[i].value = -1;
clone.outs[i].script.buffer = [];
}
}
}
var buffer = Crypto.util.hexToBytes(clone.serialize());
buffer = buffer.concat(coinjs.numToBytes(parseInt(1),4));
buffer = buffer.concat(coinjs.numToBytes(parseInt(shType), 4));
var hash = Crypto.SHA256(buffer, {asBytes: true});
var r = Crypto.util.bytesToHex(Crypto.SHA256(hash, {asBytes: true}));
return r;
@@ -892,15 +1011,124 @@
}
}
/* generate a segwit transaction hash to sign from a transaction input */
r.transactionHashSegWitV0 = function(index, sigHashType){
/*
Notice: coinb.in by default, deals with segwit transactions in a non-standard way.
Segwit transactions require that input values are included in the transaction hash.
To save wasting resources and potentially slowing down this service, we include the amount with the
redeem script to generate the transaction hash and remove it after its signed.
*/
// start redeem script check
var extract = this.extractScriptKey(index);
if(extract['type'] != 'segwit'){
return {'result':0, 'fail':'redeemscript', 'response':'redeemscript missing or not valid for segwit'};
}
var scriptcode = Crypto.util.hexToBytes(extract['script']);
if(scriptcode[0] != 0){
return {'result':0, 'fail':'scriptcode', 'response':'redeemscript is not valid'};
}
if(extract['value'] == -1){
return {'result':0, 'fail':'value', 'response':'unable to generate a valid segwit hash without a value'};
}
// end of redeem script check
scriptcode = scriptcode.slice(1);
scriptcode.unshift(25, 118, 169);
scriptcode.push(136, 172);
var value = coinjs.numToBytes(extract['value'], 8);
// start
var zero = coinjs.numToBytes(0, 32);
var version = coinjs.numToBytes(parseInt(this.version), 4);
var bufferTmp = [];
if(!(sigHashType >= 80)){ // not sighash anyonecanpay
for(var i = 0; i < this.ins.length; i++){
bufferTmp = bufferTmp.concat(Crypto.util.hexToBytes(this.ins[i].outpoint.hash).reverse());
bufferTmp = bufferTmp.concat(coinjs.numToBytes(this.ins[i].outpoint.index, 4));
}
}
var hashPrevouts = bufferTmp.length >= 1 ? Crypto.SHA256(Crypto.SHA256(bufferTmp, {asBytes: true}), {asBytes: true}) : zero;
var bufferTmp = [];
if(!(sigHashType >= 80) && sigHashType != 2 && sigHashType != 3){ // not sighash anyonecanpay & single & none
for(var i = 0; i < this.ins.length; i++){
bufferTmp = bufferTmp.concat(coinjs.numToBytes(this.ins[i].sequence, 4));
}
}
var hashSequence = bufferTmp.length >= 1 ? Crypto.SHA256(Crypto.SHA256(bufferTmp, {asBytes: true}), {asBytes: true}) : zero;
var outpoint = Crypto.util.hexToBytes(this.ins[index].outpoint.hash).reverse();
outpoint = outpoint.concat(coinjs.numToBytes(this.ins[index].outpoint.index, 4));
var nsequence = coinjs.numToBytes(this.ins[index].sequence, 4);
var hashOutputs = zero;
var bufferTmp = [];
if(sigHashType != 2 && sigHashType != 3){ // not sighash single & none
for(var i = 0; i < this.outs.length; i++ ){
bufferTmp = bufferTmp.concat(coinjs.numToBytes(this.outs[i].value, 8));
bufferTmp = bufferTmp.concat(coinjs.numToVarInt(this.outs[i].script.buffer.length));
bufferTmp = bufferTmp.concat(this.outs[i].script.buffer);
}
hashOutputs = Crypto.SHA256(Crypto.SHA256(bufferTmp, {asBytes: true}), {asBytes: true});
} else if ((sigHashType == 2) && index < this.outs.length){ // is sighash single
bufferTmp = bufferTmp.concat(coinjs.numToBytes(this.outs[index].value, 8));
bufferTmp = bufferTmp.concat(coinjs.numToVarInt(this.outs[i].script.buffer.length));
bufferTmp = bufferTmp.concat(this.outs[index].script.buffer);
hashOutputs = Crypto.SHA256(Crypto.SHA256(bufferTmp, {asBytes: true}), {asBytes: true});
}
var locktime = coinjs.numToBytes(this.lock_time, 4);
var sighash = coinjs.numToBytes(sigHashType, 4);
var buffer = [];
buffer = buffer.concat(version);
buffer = buffer.concat(hashPrevouts);
buffer = buffer.concat(hashSequence);
buffer = buffer.concat(outpoint);
buffer = buffer.concat(scriptcode);
buffer = buffer.concat(value);
buffer = buffer.concat(nsequence);
buffer = buffer.concat(hashOutputs);
buffer = buffer.concat(locktime);
buffer = buffer.concat(sighash);
var hash = Crypto.SHA256(buffer, {asBytes: true});
return {'result':1,'hash':Crypto.util.bytesToHex(Crypto.SHA256(hash, {asBytes: true})), 'response':'hash generated'};
}
/* extract the scriptSig, used in the transactionHash() function */
r.extractScriptKey = function(index) {
if(this.ins[index]){
if((this.ins[index].script.chunks.length==5) && this.ins[index].script.chunks[4]==172 && coinjs.isArray(this.ins[index].script.chunks[2])){ //OP_CHECKSIG
// regular scriptPubkey (not signed)
return {'type':'scriptpubkey', 'signed':'false', 'signatures':0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
} else if((this.ins[index].script.chunks.length==2) && this.ins[index].script.chunks[0][0]==48 && this.ins[index].script.chunks[1].length == 5 && this.ins[index].script.chunks[1][1]==177){//OP_CHECKLOCKTIMEVERIFY
// hodl script (signed)
return {'type':'hodl', 'signed':'true', 'signatures':1, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
} else if((this.ins[index].script.chunks.length==2) && this.ins[index].script.chunks[0][0]==48){
// regular scriptPubkey (probably signed)
return {'type':'scriptpubkey', 'signed':'true', 'signatures':1, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
} else if(this.ins[index].script.chunks.length == 5 && this.ins[index].script.chunks[1] == 177){//OP_CHECKLOCKTIMEVERIFY
// hodl script (not signed)
return {'type':'hodl', 'signed':'false', 'signatures': 0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)};
} else if((this.ins[index].script.chunks.length <= 3 && this.ins[index].script.chunks.length > 0) && this.ins[index].script.chunks[0].length == 22 && this.ins[index].script.chunks[0][0] == 0){
// segwit script
var signed = ((this.witness[index]) && this.witness[index].length==2) ? 'true' : 'false';
var sigs = (signed == 'true') ? 1 : 0;
var value = -1; // no value found
if((this.ins[index].script.chunks[2]) && this.ins[index].script.chunks[2].length==8){
value = coinjs.bytesToNum(this.ins[index].script.chunks[2]); // value found encoded in transaction (THIS IS NON STANDARD)
}
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])};
@@ -920,7 +1148,7 @@
}
/* generate a signature from a transaction hash */
r.transactionSig = function(index, wif){
r.transactionSig = function(index, wif, sigHashType, txhash){
function serializeSig(r, s) {
var rBa = r.toByteArraySigned();
@@ -941,7 +1169,8 @@
return sequence;
}
var hash = Crypto.util.hexToBytes(this.transactionHash(index));
var shType = sigHashType || 1;
var hash = txhash || Crypto.util.hexToBytes(this.transactionHash(index, shType));
if(hash){
var curve = EllipticCurve.getSECCurveByName("secp256k1");
@@ -966,7 +1195,7 @@
};
var sig = serializeSig(r, s);
sig.push(parseInt(1, 10));
sig.push(parseInt(shType, 10));
return Crypto.util.bytesToHex(sig);
} else {
@@ -995,12 +1224,10 @@
// hash is a byteArray of the message digest. so h1 == hash in our case
// Step: b
var v = new Uint8Array(32);
v = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
var v = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
// Step: c
var k = new Uint8Array(32);
k = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
var k = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
// Step: d
k = Crypto.HMAC(Crypto.SHA256, v.concat([0]).concat(x).concat(hash), k, { asBytes: true });
@@ -1039,9 +1266,10 @@
};
/* sign a "standard" input */
r.signinput = function(index, wif){
r.signinput = function(index, wif, sigHashType){
var key = coinjs.wif2pubkey(wif);
var signature = this.transactionSig(index, wif);
var shType = sigHashType || 1;
var signature = this.transactionSig(index, wif, shType);
var s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(signature));
s.writeBytes(Crypto.util.hexToBytes(key['pubkey']));
@@ -1049,8 +1277,20 @@
return true;
}
/* signs a time locked / hodl input */
r.signhodl = function(index, wif, sigHashType){
var shType = sigHashType || 1;
var signature = this.transactionSig(index, wif, shType);
var redeemScript = this.ins[index].script.buffer
var s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(signature));
s.writeBytes(redeemScript);
this.ins[index].script = s;
return true;
}
/* sign a multisig input */
r.signmultisig = function(index, wif){
r.signmultisig = function(index, wif, sigHashType){
function scriptListPubkey(redeemScript){
var r = {};
@@ -1062,46 +1302,87 @@
function scriptListSigs(scriptSig){
var r = {};
var c = 0;
if (scriptSig.chunks[0]==0 && scriptSig.chunks[scriptSig.chunks.length-1][scriptSig.chunks[scriptSig.chunks.length-1].length-1]==174){
for(var i=1;i<scriptSig.chunks.length-1;i++){
r[i] = scriptSig.chunks[i];
if (scriptSig.chunks[i] != 0){
c++;
r[c] = scriptSig.chunks[i];
}
}
}
return r;
}
var redeemScript = (this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]==174) ? this.ins[index].script.buffer : this.ins[index].script.chunks[this.ins[index].script.chunks.length-1];
var sighash = Crypto.util.hexToBytes(this.transactionHash(index));
var signature = Crypto.util.hexToBytes(this.transactionSig(index, wif));
var pubkeyList = scriptListPubkey(coinjs.script(redeemScript));
var sigsList = scriptListSigs(this.ins[index].script);
var shType = sigHashType || 1;
var sighash = Crypto.util.hexToBytes(this.transactionHash(index, shType));
var signature = Crypto.util.hexToBytes(this.transactionSig(index, wif, shType));
sigsList[coinjs.countObject(sigsList)+1] = signature;
var s = coinjs.script();
s.writeOp(0);
if(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]==174){
s.writeBytes(signature);
} 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){
var pubkeyList = scriptListPubkey(coinjs.script(redeemScript));
var sigsList = scriptListSigs(this.ins[index].script);
sigsList[coinjs.countObject(sigsList)+1] = signature;
for(x in pubkeyList){
for(y in sigsList){
this.ins[index].script.buffer = redeemScript;
sighash = Crypto.util.hexToBytes(this.transactionHash(index, sigsList[y].slice(-1)[0]*1));
if(coinjs.verifySignature(sighash, sigsList[y], pubkeyList[x])){
s.writeBytes(sigsList[y]);
}
}
}
}
s.writeBytes(redeemScript);
this.ins[index].script = s;
return true;
}
/* sign segwit input */
r.signsegwit = function(index, wif, sigHashType){
var shType = sigHashType || 1;
var wif2 = coinjs.wif2pubkey(wif);
var segwit = coinjs.segwitAddress(wif2['pubkey']);
if(segwit['redeemscript'] == Crypto.util.bytesToHex(this.ins[index].script.chunks[0])){
var txhash = this.transactionHashSegWitV0(index, shType);
if(txhash.result == 1){
var segwitHash = Crypto.util.hexToBytes(txhash.hash);
var signature = this.transactionSig(index, wif, shType, segwitHash);
// remove any non standard data we store, i.e. input value
var script = coinjs.script();
script.writeBytes(this.ins[index].script.chunks[0]);
this.ins[index].script = script;
this.witness.push([signature, wif2['pubkey']]);
/* reorder witness data */
var witness_order = [];
for(var i = 0; i < this.ins.length; i++){
for(var y = 0; y < this.witness.length; y++){
var sw = coinjs.segwitAddress(this.witness[y][1]);
if(sw['redeemscript'] == Crypto.util.bytesToHex(this.ins[i].script.chunks[0])){
witness_order.push(this.witness[y]);
}
}
}
this.witness = witness_order;
}
}
return true;
}
/* sign inputs */
r.sign = function(wif){
r.sign = function(wif, sigHashType){
var shType = sigHashType || 1;
for (var i = 0; i < this.ins.length; i++) {
var d = this.extractScriptKey(i);
@@ -1110,9 +1391,17 @@
var pubkeyHash = script.pubkeyHash(w2a['address']);
if(((d['type'] == 'scriptpubkey' && d['script']==Crypto.util.bytesToHex(pubkeyHash.buffer)) || d['type'] == 'empty') && d['signed'] == "false"){
this.signinput(i, wif);
this.signinput(i, wif, shType);
} else if (d['type'] == 'hodl' && d['signed'] == "false") {
this.signhodl(i, wif, shType);
} else if (d['type'] == 'multisig') {
this.signmultisig(i, wif);
this.signmultisig(i, wif, shType);
} else if (d['type'] == 'segwit') {
this.signsegwit(i, wif, shType);
} else {
// could not sign
}
@@ -1124,8 +1413,12 @@
r.serialize = function(){
var buffer = [];
buffer = buffer.concat(coinjs.numToBytes(parseInt(this.version),4));
buffer = buffer.concat(coinjs.numToVarInt(this.ins.length));
if(this.witness.length>=1){
buffer = buffer.concat([0x00, 0x01]);
}
buffer = buffer.concat(coinjs.numToVarInt(this.ins.length));
for (var i = 0; i < this.ins.length; i++) {
var txin = this.ins[i];
buffer = buffer.concat(Crypto.util.hexToBytes(txin.outpoint.hash).reverse());
@@ -1145,6 +1438,16 @@
buffer = buffer.concat(scriptBytes);
}
if(this.witness.length>=1){
for(var i = 0; i < this.witness.length; i++){
buffer = buffer.concat(coinjs.numToVarInt(this.witness[i].length));
for(var x = 0; x < this.witness[i].length; x++){
buffer = buffer.concat(coinjs.numToVarInt(Crypto.util.hexToBytes(this.witness[i][x]).length));
buffer = buffer.concat(Crypto.util.hexToBytes(this.witness[i][x]));
}
}
}
buffer = buffer.concat(coinjs.numToBytes(parseInt(this.lock_time),4));
return Crypto.util.bytesToHex(buffer);
}
@@ -1156,6 +1459,8 @@
}
var pos = 0;
var witness = false;
var readAsInt = function(bytes) {
if (bytes == 0) return 0;
pos++;
@@ -1181,8 +1486,15 @@
}
var obj = new coinjs.transaction();
obj.version = readAsInt(4);
if(buffer[pos] == 0x00 && buffer[pos+1] == 0x01){
// segwit transaction
witness = true;
obj.witness = [];
pos += 2;
}
var ins = readVarInt();
for (var i = 0; i < ins; i++) {
obj.ins.push({
@@ -1203,6 +1515,21 @@
});
}
if(witness == true){
for (i = 0; i < ins; ++i) {
var count = readVarInt();
var vector = [];
for(var y = 0; y < count; y++){
var slice = readVarInt();
pos += slice;
if(!coinjs.isArray(obj.witness[i])){
obj.witness[i] = [];
}
obj.witness[i].push(Crypto.util.bytesToHex(buffer.slice(pos - slice, pos)));
}
}
}
obj.lock_time = readAsInt(4);
return obj;
}
@@ -1373,7 +1700,7 @@
/* clone an object */
coinjs.clone = function(obj) {
if(obj == null || typeof(obj) != 'object') return obj;
var temp = obj.constructor();
var temp = new obj.constructor();
for(var key in obj) {
if(obj.hasOwnProperty(key)) {
@@ -1384,14 +1711,24 @@
}
coinjs.numToBytes = function(num,bytes) {
if (typeof bytes === undefined) bytes = 8;
if (typeof bytes === "undefined") bytes = 8;
if (bytes == 0) {
return [];
} else if (num == -1){
return Crypto.util.hexToBytes("ffffffffffffffff");
} else {
return [num % 256].concat(coinjs.numToBytes(Math.floor(num / 256),bytes-1));
}
}
coinjs.numToByteArray = function(num) {
if (num <= 256) {
return [num];
} else {
return [num % 256].concat(coinjs.numToByteArray(Math.floor(num / 256)));
}
}
coinjs.numToVarInt = function(num) {
if (num < 253) {
return [num];
@@ -1400,7 +1737,7 @@
} else if (num < 4294967296) {
return [254].concat(coinjs.numToBytes(num,4));
} else {
return [253].concat(coinjs.numToBytes(num,8));
return [255].concat(coinjs.numToBytes(num,8));
}
}
+609 -91
View File
@@ -2,6 +2,10 @@ $(document).ready(function() {
/* open wallet code */
var explorer_tx = "https://coinb.in/tx/"
var explorer_addr = "https://coinb.in/addr/"
var explorer_block = "https://coinb.in/block/"
$("#openBtn").click(function(){
var email = $("#openEmail").val().toLowerCase();
if(email.match(/[\s\w\d]+@[\s\w\d]+/g)){
@@ -26,7 +30,7 @@ $(document).ready(function() {
var keys = coinjs.newKeys(s);
$("#walletAddress").html(keys.address);
$("#walletHistory").attr('href','https://btc.blockr.io/address/info/'+keys.address);
$("#walletHistory").attr('href',explorer_addr+keys.address);
$("#walletQrCode").html("");
var qrcode = new QRCode("walletQrCode");
@@ -63,7 +67,7 @@ $(document).ready(function() {
$("#openWallet").addClass("hidden").show();
$("#walletAddress").html("");
$("#walletHistory").attr('href','https://btc.blockr.io/address/info/');
$("#walletHistory").attr('href',explorer_addr);
$("#walletQrCode").html("");
var qrcode = new QRCode("walletQrCode");
@@ -99,17 +103,22 @@ $(document).ready(function() {
$.each($("#walletSpendTo .output"), function(i,o){
var addr = $('.addressTo',o);
var amount = $('.amount',o);
if(amount.val()*1>0){
total += amount.val()*1;
tx.addoutput(addr.val(), amount.val()*1);
}
});
thisbtn.attr('disabled',true);
tx.addUnspent($("#walletAddress").html(), function(data){
var dvalue = data.value/100000000
var dvalue = (data.value/100000000).toFixed(8) * 1;
total = (total*1).toFixed(8) * 1;
if(dvalue>=total){
var change = dvalue-total;
if(change>0){
if((change*1)>0){
tx.addoutput($("#walletAddress").html(), change);
}
@@ -126,6 +135,9 @@ $(document).ready(function() {
$("#walletSendConfirmStatus").removeClass('hidden').addClass('alert-success').html("txid: "+$(data).find("txid").text());
} else {
$("#walletSendConfirmStatus").removeClass('hidden').addClass('alert-danger').html(unescape($(data).find("response").text()).replace(/\+/g,' '));
$("#walletSendFailTransaction").removeClass('hidden');
$("#walletSendFailTransaction textarea").val(signed);
thisbtn.attr('disabled',false);
}
// update wallet balance
@@ -133,16 +145,17 @@ $(document).ready(function() {
}, signed);
} else {
$("#walletSendConfirmStatus").removeClass("hidden").addClass('alert-danger').html("You have a confirmed balance of "+data.value+" BTC unable to send "+total+" BTC").fadeOut().fadeIn();
$("#walletSendConfirmStatus").removeClass("hidden").addClass('alert-danger').html("You have a confirmed balance of "+dvalue+" BTC unable to send "+total+" BTC").fadeOut().fadeIn();
thisbtn.attr('disabled',false);
}
thisbtn.attr('disabled',false);
$("#walletLoader").addClass("hidden");
});
});
$("#walletSendBtn").click(function(){
$("#walletSendFailTransaction").addClass('hidden');
$("#walletSendStatus").addClass("hidden").html("");
var thisbtn = $(this);
@@ -272,6 +285,14 @@ $(document).ready(function() {
}
});
$("#newSegWitBrainwallet").click(function(){
if($(this).is(":checked")){
$("#brainwalletSegWit").removeClass("hidden");
} else {
$("#brainwalletSegWit").addClass("hidden");
}
});
$("#encryptKey").click(function(){
if($(this).is(":checked")){
$("#aes256passform").removeClass("hidden");
@@ -280,6 +301,21 @@ $(document).ready(function() {
}
});
/* new -> segwit code */
$("#newSegWitKeysBtn").click(function(){
var compressed = coinjs.compressed;
coinjs.compressed = true;
var s = ($("#newSegWitBrainwallet").is(":checked")) ? $("#brainwalletSegWit").val() : null;
var coin = coinjs.newKeys(s);
var sw = coinjs.segwitAddress(coin.pubkey);
$("#newSegWitAddress").val(sw.address);
$("#newSegWitRedeemScript").val(sw.redeemscript);
$("#newSegWitPubKey").val(coin.pubkey);
$("#newSegWitPrivKey").val(coin.wif);
coinjs.compressed = compressed;
});
/* new -> multisig code */
$("#newMultiSigAddress").click(function(){
@@ -331,6 +367,95 @@ $(document).ready(function() {
}
});
$("#mediatorList").change(function(){
var data = ($(this).val()).split(";");
$("#mediatorPubkey").val(data[0]);
$("#mediatorEmail").val(data[1]);
$("#mediatorFee").val(data[2]);
}).change();
$("#mediatorAddKey").click(function(){
var count = 0;
var len = $(".pubkeyRemove").length;
if(len<14){
$.each($("#multisigPubKeys .pubkey"),function(i,o){
if($(o).val()==''){
$(o).val($("#mediatorPubkey").val()).fadeOut().fadeIn();
$("#mediatorClose").click();
return false;
} else if(count==len){
$("#multisigPubKeys .pubkeyAdd").click();
$("#mediatorAddKey").click();
return false;
}
count++;
});
$("#mediatorClose").click();
}
});
/* new -> time locked code */
$('#timeLockedDateTimePicker').datetimepicker({
format: "MM/DD/YYYY HH:mm",
});
$('#timeLockedRbTypeBox input').change(function(){
if ($('#timeLockedRbTypeDate').is(':checked')){
$('#timeLockedDateTimePicker').show();
$('#timeLockedBlockHeight').hide();
} else {
$('#timeLockedDateTimePicker').hide();
$('#timeLockedBlockHeight').removeClass('hidden').show();
}
});
$("#newTimeLockedAddress").click(function(){
$("#timeLockedData").removeClass('show').addClass('hidden').fadeOut();
$("#timeLockedPubKey").parent().removeClass('has-error');
$("#timeLockedDateTimePicker").parent().removeClass('has-error');
$("#timeLockedErrorMsg").hide();
if(!coinjs.pubkeydecompress($("#timeLockedPubKey").val())) {
$('#timeLockedPubKey').parent().addClass('has-error');
}
var nLockTime = -1;
if ($('#timeLockedRbTypeDate').is(':checked')){
// by date
var date = $('#timeLockedDateTimePicker').data("DateTimePicker").date();
if(!date || !date.isValid()) {
$('#timeLockedDateTimePicker').parent().addClass('has-error');
}
nLockTime = date.unix()
if (nLockTime < 500000000) {
$('#timeLockedDateTimePicker').parent().addClass('has-error');
}
} else {
nLockTime = parseInt($('#timeLockedBlockHeightVal').val(), 10);
if (nLockTime >= 500000000) {
$('#timeLockedDateTimePicker').parent().addClass('has-error');
}
}
if(($("#timeLockedPubKey").parent().hasClass('has-error')==false) && $("#timeLockedDateTimePicker").parent().hasClass('has-error')==false){
try {
var hodl = coinjs.simpleHodlAddress($("#timeLockedPubKey").val(), nLockTime);
$("#timeLockedData .address").val(hodl['address']);
$("#timeLockedData .script").val(hodl['redeemScript']);
$("#timeLockedData .scriptUrl").val(document.location.origin+''+document.location.pathname+'?verify='+hodl['redeemScript']+'#verify');
$("#timeLockedData").removeClass('hidden').addClass('show').fadeIn();
} catch(e) {
$("#timeLockedErrorMsg").html('<span class="glyphicon glyphicon-exclamation-sign"></span> ' + e).fadeIn();
}
} else {
$("#timeLockedErrorMsg").html('<span class="glyphicon glyphicon-exclamation-sign"></span> Public key and/or date is invalid!').fadeIn();
}
});
/* new -> Hd address code */
$(".deriveHDbtn").click(function(){
@@ -397,14 +522,49 @@ $(document).ready(function() {
$("#transactionBtn").click(function(){
var tx = coinjs.transaction();
var estimatedTxSize = 10; // <4:version><1:txInCount><1:txOutCount><4:nLockTime>
$("#transactionCreate, #transactionCreateStatus").addClass("hidden");
if(($("#nLockTime").val()).match(/^[0-9]+$/g)){
tx.lock_time = $("#nLockTime").val()*1;
}
$("#inputs .row").removeClass('has-error');
$('#putTabs a[href="#txinputs"], #putTabs a[href="#txoutputs"]').attr('style','');
$.each($("#inputs .row"), function(i,o){
if($(".txId",o).val()!="" && $(".txIdN",o).val()!=""){
tx.addinput($(".txId",o).val(), $(".txIdN",o).val(), $(".txIdScript",o).val());
if(!($(".txId",o).val()).match(/^[a-f0-9]+$/i)){
$(o).addClass("has-error");
} else if((!($(".txIdScript",o).val()).match(/^[a-f0-9]+$/i)) && $(".txIdScript",o).val()!=""){
$(o).addClass("has-error");
} else if (!($(".txIdN",o).val()).match(/^[0-9]+$/i)){
$(o).addClass("has-error");
}
if(!$(o).hasClass("has-error")){
var seq = null;
if($("#txRBF").is(":checked")){
seq = 0xffffffff-2;
}
var currentScript = $(".txIdScript",o).val();
if (currentScript.match(/^76a914[0-9a-f]{40}88ac$/)) {
estimatedTxSize += 147
} else if (currentScript.match(/^5[1-9a-f](?:210[23][0-9a-f]{64}){1,15}5[1-9a-f]ae$/)) {
// <74:persig <1:push><72:sig><1:sighash> ><34:perpubkey <1:push><33:pubkey> > <32:prevhash><4:index><4:nSequence><1:m><1:n><1:OP>
var scriptSigSize = (parseInt(currentScript.slice(1,2),16) * 74) + (parseInt(currentScript.slice(-3,-2),16) * 34) + 43
// varint 2 bytes if scriptSig is > 252
estimatedTxSize += scriptSigSize + (scriptSigSize > 252 ? 2 : 1)
} else {
// underestimating won't hurt. Just showing a warning window anyways.
estimatedTxSize += 147
}
tx.addinput($(".txId",o).val(), $(".txIdN",o).val(), $(".txIdScript",o).val(), seq);
} else {
$('#putTabs a[href="#txinputs"]').attr('style','color:#a94442;');
}
});
@@ -413,21 +573,38 @@ $(document).ready(function() {
$.each($("#recipients .row"), function(i,o){
var a = ($(".address",o).val());
var ad = coinjs.addressDecode(a);
if(((a!="") && (ad.version == coinjs.pub || ad.version == coinjs.priv)) && $(".amount",o).val()!=""){ // address
if(((a!="") && (ad.version == coinjs.pub || ad.version == coinjs.multisig)) && $(".amount",o).val()!=""){ // address
// P2SH output is 32, P2PKH is 34
estimatedTxSize += (ad.version == coinjs.pub ? 34 : 32)
tx.addoutput(a, $(".amount",o).val());
} else if (((a!="") && ad.version === 42) && $(".amount",o).val()!=""){ // stealth address
// 1 P2PKH and 1 OP_RETURN with 36 bytes, OP byte, and 8 byte value
estimatedTxSize += 78
tx.addstealth(ad, $(".amount",o).val());
} else if (((($("#opReturn").is(":checked")) && a.match(/^[a-f0-9]+$/ig)) && a.length<80) && (a.length%2)==0) { // data
} else if (((($("#opReturn").is(":checked")) && a.match(/^[a-f0-9]+$/ig)) && a.length<160) && (a.length%2)==0) { // data
estimatedTxSize += (a.length / 2) + 1 + 8
tx.adddata(a);
} else { // neither address nor data
$(o).addClass('has-error');
$('#putTabs a[href="#txoutputs"]').attr('style','color:#a94442;');
}
});
if(!$("#recipients .row, #inputs .row").hasClass('has-error')){
$("#transactionCreate textarea").val(tx.serialize());
$("#transactionCreate .txSize").html(tx.size());
$("#transactionCreate").removeClass("hidden");
// Check fee against hard 0.01 as well as fluid 200 satoshis per byte calculation.
if($("#transactionFee").val()>=0.01 || $("#transactionFee").val()>= estimatedTxSize * 200 * 1e-8){
$("#modalWarningFeeAmount").html($("#transactionFee").val());
$("#modalWarningFee").modal("show");
}
} else {
$("#transactionCreateStatus").removeClass("hidden").html("One or more input or output is invalid").fadeOut().fadeIn();
}
});
$(".txidClear").click(function(){
@@ -442,6 +619,29 @@ $(document).ready(function() {
totalInputAmount();
});
$("#donateTxBtn").click(function(){
var exists = false;
$.each($("#recipients .address"), function(i,o){
if($(o).val() == coinjs.developer){
exists = true;
$(o).fadeOut().fadeIn();
return true;
}
});
if(!exists){
if($("#recipients .recipient:last .address:last").val() != ""){
$("#recipients .addressAddTo:first").click();
};
$("#recipients .recipient:last .address:last").val(coinjs.developer).fadeOut().fadeIn();
return true;
}
});
/* code for the qr code scanner */
$(".qrcodeScanner").click(function(){
@@ -507,71 +707,272 @@ $(document).ready(function() {
}
}
/* redeem from button code */
$("#redeemFromBtn").click(function(){
var thisbtn = this;
var addr = '';
var isMultiSig = false;
var s = $("#redeemFrom").val();
var redeem = redeemingFrom($("#redeemFrom").val());
$("#redeemFromStatus, #redeemFromAddress").addClass('hidden');
$(thisbtn).html("Please wait, loading...").attr('disabled',true);
var decode = coinjs.addressDecode(s);
if(decode.version == coinjs.pub){
addr = s;
} else if (decode.version == coinjs.priv){
var a = coinjs.wif2address(s);
addr = a['address'];
} else if (decode.version == coinjs.multisig){
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!');
} else {
var script = coinjs.script();
var decodeRs = script.decodeRedeemScript(s);
if(decodeRs){
addr = decodeRs['address'];
isMultiSig = true;
} else {
// input is neither a regular address or redeem script
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> The address or multisig redeem script you have entered is invalid');
}
return false;
}
if(redeem.from=='other'){
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> The address or multisig redeem script you have entered is invalid');
return false;
}
var tx = coinjs.transaction();
tx.listUnspent(addr, function(data){
if(addr) {
if($("#clearInputsOnLoad").is(":checked")){
$("#inputs .txidRemove, #inputs .txidClear").click();
}
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="https://btc.blockr.io/address/info/'+addr+'" target="_blank">'+addr+'</a>');
$("#redeemFromBtn").html("Please wait, loading...").attr('disabled',true);
$.each($(data).find("unspent").children(), function(i,o){
var host = $(this).attr('rel');
if(host=='chain.so_litecoin'){
listUnspentChainso_Litecoin(redeem);
} else if(host=='chain.so_dogecoin'){
listUnspentChainso_Dogecoin(redeem);
} else if(host=='cryptoid.info_carboncoin'){
listUnspentCryptoidinfo_Carboncoin(redeem);
} else {
listUnspentDefault(redeem);
}
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);
} else {
$("#nLockTime").val(0);
}
}
});
/* function to determine what we are redeeming from */
function redeemingFrom(string){
var r = {};
var decode = coinjs.addressDecode(string);
if(decode.version == coinjs.pub){ // regular address
r.addr = string;
r.from = 'address';
r.isMultisig = false;
} else if (decode.version == coinjs.priv){ // wif key
var a = coinjs.wif2address(string);
r.addr = a['address'];
r.from = 'wif';
r.isMultisig = false;
} else if (decode.version == coinjs.multisig){ // mulisig address
r.addr = '';
r.from = 'multisigAddress';
r.isMultisig = false;
} else {
var script = coinjs.script();
var decodeRs = script.decodeRedeemScript(string);
if(decodeRs){ // redeem script
r.addr = decodeRs['address'];
r.from = 'redeemScript';
r.decodedRs = decodeRs;
r.isMultisig = true; // not quite, may be hodl
} else { // something else
r.addr = '';
r.from = 'other';
r.isMultisig = false;
}
}
return r;
}
/* mediator payment code for when you used a public key */
function mediatorPayment(redeem){
if(redeem.from=="redeemScript"){
$('#recipients .row[rel="'+redeem.addr+'"]').parent().remove();
$.each(redeem.decodedRs.pubkeys, function(i, o){
$.each($("#mediatorList option"), function(mi, mo){
var ms = ($(mo).val()).split(";");
var pubkey = ms[0]; // mediators pubkey
var fee = ms[2]*1; // fee in a percentage
var payto = coinjs.pubkey2address(pubkey); // pay to mediators address
if(o==pubkey){ // matched a mediators pubkey?
var clone = '<span><div class="row recipients mediator mediator_'+pubkey+'" rel="'+redeem.addr+'">'+$("#recipients .addressAddTo").parent().parent().html()+'</div><br></span>';
$("#recipients").prepend(clone);
$("#recipients .mediator_"+pubkey+" .glyphicon-plus:first").removeClass('glyphicon-plus');
$("#recipients .mediator_"+pubkey+" .address:first").val(payto).attr('disabled', true).attr('readonly',true).attr('title','Medation fee for '+$(mo).html());
var amount = ((fee*$("#totalInput").html())/100).toFixed(8);
$("#recipients .mediator_"+pubkey+" .amount:first").attr('disabled',(((amount*1)==0)?false:true)).val(amount).attr('title','Medation fee for '+$(mo).html());
}
});
});
validateOutputAmount();
}
}
/* global function to add outputs to page */
function addOutput(tx, n, script, amount) {
if(tx){
if($("#inputs .txId:last").val()!=""){
$("#inputs .txidAdd").click();
}
$("#inputs .row:last input").attr('disabled',true);
var val = (($(o).find("value").text()*1)/100000000);
var txid = (($(o).find("tx_hash").text()).match(/.{1,2}/g).reverse()).join("")+'';
var txid = ((tx).match(/.{1,2}/g).reverse()).join("")+'';
$("#inputs .txId:last").val(txid);
$("#inputs .txIdN:last").val($(o).find("tx_output_n").text());
$("#inputs .txIdAmount:last").val(val.toFixed(8));
if(isMultiSig==true){
$("#inputs .txIdScript:last").val(s);
$("#inputs .txIdN:last").val(n);
$("#inputs .txIdAmount:last").val(amount);
if(script.match(/^00/) && script.length==44){
s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(script));
s.writeOp(0);
s.writeBytes(coinjs.numToBytes((amount*100000000).toFixed(0), 8));
script = Crypto.util.bytesToHex(s.buffer);
}
$("#inputs .txIdScript:last").val(script);
}
}
/* default function to retreive unspent outputs*/
function listUnspentDefault(redeem){
var tx = coinjs.transaction();
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>');
$.each($(data).find("unspent").children(), function(i,o){
var tx = $(o).find("tx_hash").text();
var n = $(o).find("tx_output_n").text();
var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : $(o).find("script").text();
var amount = (($(o).find("value").text()*1)/100000000).toFixed(8);
addOutput(tx, n, script, amount);
});
}
$("#redeemFromBtn").html("Load").attr('disabled',false);
totalInputAmount();
mediatorPayment(redeem);
});
}
/* retrieve unspent data from chainso for litecoin */
function listUnspentChainso_Litecoin(redeem){
$.ajax ({
type: "GET",
url: "https://chain.so/api/v2/get_tx_unspent/ltc/"+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>');
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.isMultisig==true) ? $("#redeemFrom").val() : o.script_hex;
var amount = o.value;
addOutput(tx, n, script, amount);
}
} else {
$("#inputs .txIdScript:last").val($(o).find("script").text());
$("#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();
}
});
}
$(thisbtn).html("Load").attr('disabled',false);
/* retrieve unspent data from chain.so for carboncoin */
function listUnspentCryptoidinfo_Carboncoin(redeem) {
$.ajax ({
type: "POST",
url: "https://coinb.in/api/",
data: 'uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=carboncoin&request=listunspent&address='+redeem.addr,
dataType: "xml",
error: function() {
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
},
success: function(data) {
if($(data).find("result").text()==1){
$("#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>');
$.each($(data).find("unspent").children(), function(i,o){
var tx = $(o).find("tx_hash").text();
var n = $(o).find("tx_output_n").text();
var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.script_hex;
var amount = (($(o).find("value").text()*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 chain.so for dogecoin */
function listUnspentChainso_Dogecoin(redeem){
$.ajax ({
type: "GET",
url: "https://chain.so/api/v2/get_tx_unspent/doge/"+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>');
for(var i in data.data.txs){
var o = data.data.txs[i];
var tx = ((""+o.txid).match(/.{1,2}/g).reverse()).join("")+'';
if(tx.match(/^[a-f0-9]+$/)){
var n = o.output_no;
var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.script_hex;
var amount = o.value;
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();
}
});
}
/* math to calculate the inputs and outputs */
function totalInputAmount(){
$("#totalInput").html('0.00');
@@ -633,9 +1034,16 @@ $(document).ready(function() {
// broadcast transaction vai coinbin (default)
function rawSubmitDefault(btn){
var thisbtn = btn;
var tx = coinjs.transaction();
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
tx.broadcast(function(data){
$.ajax ({
type: "POST",
url: coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=bitcoin&request=sendrawtransaction',
data: {'rawtx':$("#rawTransaction").val()},
dataType: "xml",
error: function(data) {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(" There was an error submitting your request, please try again").prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
},
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');
@@ -643,31 +1051,59 @@ $(document).ready(function() {
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
}
},
complete: function(data, status) {
$("#rawTransactionStatus").fadeOut().fadeIn();
$(thisbtn).val('Submit').attr('disabled',false);
}, $("#rawTransaction").val());
}
});
}
// broadcast transaction via blockr.io (mainnet)
function rawSubmitBlockrio_BitcoinMainnet(thisbtn){
// broadcast transaction via cryptoid
function rawSubmitcryptoid_Carboncoin(thisbtn) {
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://btc.blockr.io/api/v1/tx/push",
data: {"hex":$("#rawTransaction").val()},
url: coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=carboncoin&request=sendrawtransaction',
data: {'rawtx':$("#rawTransaction").val()},
dataType: "xml",
error: function(data) {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(" There was an error submitting your request, please try again").prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
},
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());
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span> ');
}
},
complete: function(data, status) {
$("#rawTransactionStatus").fadeOut().fadeIn();
$(thisbtn).val('Submit').attr('disabled',false);
}
});
}
// broadcast transaction via chain.so (mainnet)
function rawSubmitChainso_BitcoinMainnet(thisbtn){
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://chain.so/api/v2/send_tx/BTC/",
data: {"tx_hex":$("#rawTransaction").val()},
dataType: "json",
error: function(data) {
var obj = $.parseJSON(data.responseText);
var r = ' ';
r += (obj.data) ? obj.data : '';
r += (obj.message) ? ' '+obj.message : '';
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>');
},
success: function(data) {
var obj = $.parseJSON(data.responseText);
if((obj.status && obj.data) && obj.status=='success'){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+obj.data);
if(data.status && data.data.txid){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.data.txid);
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
@@ -679,26 +1115,23 @@ $(document).ready(function() {
});
}
// broadcast transaction via blockr.io (testnet)
function rawSubmitBlockrio_BitcoinTestnet(thisbtn){
// broadcast transaction via blockcypher.com (mainnet)
function rawSubmitblockcypher_BitcoinMainnet(thisbtn){
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
$.ajax ({
type: "POST",
url: "https://tbtc.blockr.io/api/v1/tx/push",
data: {"hex":$("#rawTransaction").val()},
dataType: "json",
url: "https://api.blockcypher.com/v1/btc/main/txs/push",
data: JSON.stringify({"tx":$("#rawTransaction").val()}),
error: function(data) {
var obj = $.parseJSON(data.responseText);
var r = ' ';
r += (obj.data) ? obj.data : '';
r += (obj.message) ? ' '+obj.message : '';
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>');
},
success: function(data) {
var obj = $.parseJSON(data.responseText);
if((obj.status && obj.data) && obj.status=='success'){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+obj.data);
if((data.tx) && data.tx.hash){
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.tx.hash);
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
@@ -710,6 +1143,41 @@ $(document).ready(function() {
});
}
// broadcast transaction via chain.so for dogecoin
function rawSubmitchainso_dogecoin(thisbtn){
$(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()},
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
$("#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);
} else {
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
}
},
complete: function(data, status) {
$("#rawTransactionStatus").fadeOut().fadeIn();
$(thisbtn).val('Submit').attr('disabled',false);
}
});
}
/* verify script code */
$("#verifyBtn").click(function(){
@@ -733,19 +1201,43 @@ $(document).ready(function() {
var script = coinjs.script();
var decode = script.decodeRedeemScript($("#verifyScript").val());
if(decode){
$("#verifyRsData .multisigAddress").val(decode['address']);
$("#verifyRsData .signaturesRequired").html(decode['signaturesRequired']);
$("#verifyRsData table tbody").html("");
$("#verifyRsDataMultisig").addClass('hidden');
$("#verifyRsDataHodl").addClass('hidden');
$("#verifyRsDataSegWit").addClass('hidden');
$("#verifyRsData").addClass("hidden");
if(decode.type == "multisig__") {
$("#verifyRsDataMultisig .multisigAddress").val(decode['address']);
$("#verifyRsDataMultisig .signaturesRequired").html(decode['signaturesRequired']);
$("#verifyRsDataMultisig table tbody").html("");
for(var i=0;i<decode.pubkeys.length;i++){
$('<tr><td><input type="text" class="form-control" value="'+decode.pubkeys[i]+'" readonly></td></tr>').appendTo("#verifyRsData table tbody");
var pubkey = decode.pubkeys[i];
var address = coinjs.pubkey2address(pubkey);
$('<tr><td width="30%"><input type="text" class="form-control" value="'+address+'" readonly></td><td><input type="text" class="form-control" value="'+pubkey+'" readonly></td></tr>').appendTo("#verifyRsDataMultisig table tbody");
}
$("#verifyRsData").removeClass("hidden");
$("#verifyRsDataMultisig").removeClass('hidden');
$(".verifyLink").attr('href','?verify='+$("#verifyScript").val());
return true;
} else if(decode.type == "segwit__"){
$("#verifyRsData").removeClass("hidden");
$("#verifyRsDataSegWit .segWitAddress").val(decode['address']);
$("#verifyRsDataSegWit").removeClass('hidden');
return true;
} else if(decode.type == "hodl__") {
var d = $("#verifyRsDataHodl .date").data("DateTimePicker");
$("#verifyRsDataHodl .address").val(decode['address']);
$("#verifyRsDataHodl .pubkey").val(coinjs.pubkey2address(decode['pubkey']));
$("#verifyRsDataHodl .date").val(decode['checklocktimeverify'] >= 500000000? moment.unix(decode['checklocktimeverify']).format("MM/DD/YYYY HH:mm") : decode['checklocktimeverify']);
$("#verifyRsData").removeClass("hidden");
$("#verifyRsDataHodl").removeClass('hidden');
$(".verifyLink").attr('href','?verify='+$("#verifyScript").val());
return true;
} else {
return false;
}
}
return false;
}
function decodeTransactionScript(){
var tx = coinjs.transaction();
@@ -755,6 +1247,11 @@ $(document).ready(function() {
$("#verifyTransactionData .transactionVersion").html(decode['version']);
$("#verifyTransactionData .transactionSize").html(decode.size()+' <i>bytes</i>');
$("#verifyTransactionData .transactionLockTime").html(decode['lock_time']);
$("#verifyTransactionData .transactionRBF").hide();
$("#verifyTransactionData .transactionSegWit").hide();
if (decode.witness.length>=1) {
$("#verifyTransactionData .transactionSegWit").show();
}
$("#verifyTransactionData").removeClass("hidden");
$("#verifyTransactionData tbody").html("");
@@ -765,7 +1262,7 @@ $(document).ready(function() {
h += '<td><input class="form-control" type="text" value="'+o.outpoint.hash+'" readonly></td>';
h += '<td class="col-xs-1">'+o.outpoint.index+'</td>';
h += '<td class="col-xs-2"><input class="form-control" type="text" value="'+Crypto.util.bytesToHex(o.script.buffer)+'" readonly></td>';
h += '<td class="col-xs-1"> <span class="glyphicon glyphicon-'+((s.signed=='true')?'ok':'remove')+'-circle"></span>';
h += '<td class="col-xs-1"> <span class="glyphicon glyphicon-'+((s.signed=='true' || (decode.witness[i] && decode.witness[i].length==2))?'ok':'remove')+'-circle"></span>';
if(s['type']=='multisig' && s['signatures']>=1){
h += ' '+s['signatures'];
}
@@ -780,6 +1277,11 @@ $(document).ready(function() {
}
h += '</td>';
h += '</tr>';
//debug
if(parseInt(o.sequence)<(0xFFFFFFFF-1)){
$("#verifyTransactionData .transactionRBF").show();
}
});
$(h).appendTo("#verifyTransactionData .ins tbody");
@@ -876,6 +1378,7 @@ $(document).ready(function() {
}
function decodeHDaddress(){
coinjs.compressed = true;
var s = $("#verifyScript").val();
try {
var hex = Crypto.util.bytesToHex((coinjs.base58decode(s)).slice(0,4));
@@ -946,7 +1449,7 @@ $(document).ready(function() {
var tx = coinjs.transaction();
var t = tx.deserialize(script.val());
var signed = t.sign(wifkey.val());
var signed = t.sign(wifkey.val(), $("#sighashType option:selected").val());
$("#signedData textarea").val(signed);
$("#signedData .txSize").html(t.size());
$("#signedData").removeClass('hidden').fadeIn();
@@ -959,6 +1462,19 @@ $(document).ready(function() {
}
});
$("#sighashType").change(function(){
$("#sighashTypeInfo").html($("option:selected",this).attr('rel')).fadeOut().fadeIn();
});
$("#signAdvancedCollapse").click(function(){
if($("#signAdvanced").hasClass('hidden')){
$("span",this).removeClass('glyphicon-collapse-down').addClass('glyphicon-collapse-up');
$("#signAdvanced").removeClass("hidden");
} else {
$("span",this).removeClass('glyphicon-collapse-up').addClass('glyphicon-collapse-down');
$("#signAdvanced").addClass("hidden");
}
});
/* page load code */
@@ -977,8 +1493,6 @@ $(document).ready(function() {
return r;
}
$("#newKeysBtn, #newHDKeysBtn").click();
var _getBroadcast = _get("broadcast");
if(_getBroadcast[0]){
$("#rawTransaction").val(_getBroadcast[0]);
@@ -1066,6 +1580,9 @@ $(document).ready(function() {
$("#settingsBtn").click(function(){
// log out of openwallet
$("#walletLogout").click();
$("#statusSettings").removeClass("alert-success").removeClass("alert-danger").addClass("hidden").html("");
$("#settings .has-error").removeClass("has-error");
@@ -1094,8 +1611,6 @@ $(document).ready(function() {
});
$("#coinjs_coin").change(function(){
// log out of openwallet
$("#walletLogout").click();
var o = ($("option:selected",this).attr("rel")).split(";");
@@ -1119,7 +1634,7 @@ $(document).ready(function() {
// deal with the reset
$("#coinjs_pub").val(o[0]);
$("#coinjs_prv").val(o[1]);
$("#coinjs_priv").val(o[1]);
$("#coinjs_multisig").val(o[2]);
$("#coinjs_hdpub").val(o[3]);
$("#coinjs_hdprv").val(o[4]);
@@ -1134,29 +1649,32 @@ $(document).ready(function() {
function configureBroadcast(){
var host = $("#coinjs_broadcast option:selected").val();
var tx = coinjs.transaction();
$("#rawSubmitBtn").unbind("");
if(host=="blockr.io_bitcointestnet"){
if(host=="chain.so_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){
rawSubmitBlockrio_BitcoinTestnet(this)
rawSubmitChainso_BitcoinMainnet(this);
});
} else if(host=="blockr.io_bitcoinmainnet"){
} else if(host=="chain.so_dogecoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitBlockrio_BitcoinMainnet(this);
rawSubmitchainso_dogecoin(this);
});
} else if(host=="blockcypher_bitcoinmainnet"){
$("#rawSubmitBtn").click(function(){
rawSubmitblockcypher_BitcoinMainnet(this);
});
} else if(host=="cryptoid.info_carboncoin"){
$("#rawSubmitBtn").click(function(){
rawSubmitcryptoid_Carboncoin(this);
});
} else {
$("#rawSubmitBtn").click(function(){
rawSubmitDefault(this); // revert to default
});
}
}
function configureGetUnspentTx(){
// function coming soon, which will allow you to retrieve unspent inputs
// from other block chain providers
return false;
$("#redeemFromBtn").attr('rel',$("#coinjs_utxo option:selected").val());
}
/* capture mouse movement to add entropy */
+211
View File
@@ -0,0 +1,211 @@
/* ========================================================================
* Bootstrap: collapse.js v3.3.4
* http://getbootstrap.com/javascript/#collapse
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// COLLAPSE PUBLIC CLASS DEFINITION
// ================================
var Collapse = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Collapse.DEFAULTS, options)
this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
'[data-toggle="collapse"][data-target="#' + element.id + '"]')
this.transitioning = null
if (this.options.parent) {
this.$parent = this.getParent()
} else {
this.addAriaAndCollapsedClass(this.$element, this.$trigger)
}
if (this.options.toggle) this.toggle()
}
Collapse.VERSION = '3.3.4'
Collapse.TRANSITION_DURATION = 350
Collapse.DEFAULTS = {
toggle: true
}
Collapse.prototype.dimension = function () {
var hasWidth = this.$element.hasClass('width')
return hasWidth ? 'width' : 'height'
}
Collapse.prototype.show = function () {
if (this.transitioning || this.$element.hasClass('in')) return
var activesData
var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
if (actives && actives.length) {
activesData = actives.data('bs.collapse')
if (activesData && activesData.transitioning) return
}
var startEvent = $.Event('show.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
if (actives && actives.length) {
Plugin.call(actives, 'hide')
activesData || actives.data('bs.collapse', null)
}
var dimension = this.dimension()
this.$element
.removeClass('collapse')
.addClass('collapsing')[dimension](0)
.attr('aria-expanded', true)
this.$trigger
.removeClass('collapsed')
.attr('aria-expanded', true)
this.transitioning = 1
var complete = function () {
this.$element
.removeClass('collapsing')
.addClass('collapse in')[dimension]('')
this.transitioning = 0
this.$element
.trigger('shown.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
var scrollSize = $.camelCase(['scroll', dimension].join('-'))
this.$element
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
}
Collapse.prototype.hide = function () {
if (this.transitioning || !this.$element.hasClass('in')) return
var startEvent = $.Event('hide.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
var dimension = this.dimension()
this.$element[dimension](this.$element[dimension]())[0].offsetHeight
this.$element
.addClass('collapsing')
.removeClass('collapse in')
.attr('aria-expanded', false)
this.$trigger
.addClass('collapsed')
.attr('aria-expanded', false)
this.transitioning = 1
var complete = function () {
this.transitioning = 0
this.$element
.removeClass('collapsing')
.addClass('collapse')
.trigger('hidden.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
this.$element
[dimension](0)
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)
}
Collapse.prototype.toggle = function () {
this[this.$element.hasClass('in') ? 'hide' : 'show']()
}
Collapse.prototype.getParent = function () {
return $(this.options.parent)
.find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
.each($.proxy(function (i, element) {
var $element = $(element)
this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
}, this))
.end()
}
Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
var isOpen = $element.hasClass('in')
$element.attr('aria-expanded', isOpen)
$trigger
.toggleClass('collapsed', !isOpen)
.attr('aria-expanded', isOpen)
}
function getTargetFromTrigger($trigger) {
var href
var target = $trigger.attr('data-target')
|| (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
return $(target)
}
// COLLAPSE PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.collapse')
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.collapse
$.fn.collapse = Plugin
$.fn.collapse.Constructor = Collapse
// COLLAPSE NO CONFLICT
// ====================
$.fn.collapse.noConflict = function () {
$.fn.collapse = old
return this
}
// COLLAPSE DATA-API
// =================
$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
var $this = $(this)
if (!$this.attr('data-target')) e.preventDefault()
var $target = getTargetFromTrigger($this)
var data = $target.data('bs.collapse')
var option = data ? 'toggle' : $this.data()
Plugin.call($target, option)
})
}(jQuery);
+7
View File
File diff suppressed because one or more lines are too long
+59
View File
@@ -0,0 +1,59 @@
/* ========================================================================
* Bootstrap: transition.js v3.3.4
* http://getbootstrap.com/javascript/#transitions
* ========================================================================
* Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
// ============================================================
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
WebkitTransition : 'webkitTransitionEnd',
MozTransition : 'transitionend',
OTransition : 'oTransitionEnd otransitionend',
transition : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false // explicit for ie8 ( ._.)
}
// http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) {
var called = false
var $el = this
$(this).one('bsTransitionEnd', function () { called = true })
var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
setTimeout(callback, duration)
return this
}
$(function () {
$.support.transition = transitionEnd()
if (!$.support.transition) return
$.event.special.bsTransitionEnd = {
bindType: $.support.transition.end,
delegateType: $.support.transition.end,
handle: function (e) {
if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
}
}
})
}(jQuery);
+18 -13
View File
@@ -1,22 +1,27 @@
---- Version 1.2 2015.07.23 ----
e6810907c901e6bd34a28735a68850936f0823b8 ./js/ellipticcurve.js
9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js
---- Version 1.3 2017.09.10 ----
77e4519962e2f6a9fc93342137dbb31c33b76b04 ./js/aes.js
0ce26da5ef686d4ece91acd6cb6506559e11ab07 ./js/qcode-decoder.min.js
be17ca7c834204bff711f582e41f76c06d472bac ./js/jsbn.js
0700fc9ad2e39adeca0b50614bb3d327fb49f609 ./js/crypto-sha256.js
3a09a8fc0cfe828b57fc798d668234d0490ee1a6 ./js/bootstrap-datetimepicker.min.js
253711c6d825de55a8360552573be950da180614 ./js/bootstrap.min.js
b98f718f0400fada4e0f15471031f92ce31e2b83 ./js/coinbin.js
3e7b9b1a30412f827d4709a53014d0b6f06103f0 ./js/coin.js
988565bc2cb402d63ed5c5fd7ff47c4278efc2c5 ./js/collapse.js
9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js
f7c09f2f5a721371e7d478050119f7e2d58e3ef9 ./js/crypto-sha256-hmac.js
0700fc9ad2e39adeca0b50614bb3d327fb49f609 ./js/crypto-sha256.js
e6810907c901e6bd34a28735a68850936f0823b8 ./js/ellipticcurve.js
ae49e56999d82802727455f0ba83b63acd90a22b ./js/jquery-1.9.1.min.js
be17ca7c834204bff711f582e41f76c06d472bac ./js/jsbn.js
ce4fa351a2e62accf7fad77110fa4ddb09a324bf ./js/moment.min.js
0ce26da5ef686d4ece91acd6cb6506559e11ab07 ./js/qcode-decoder.min.js
ad038e1f39646b68ae666324ed4c2882a8c42474 ./js/qrcode.js
64eb4ea5c882f8bce3e1885bf00728455f1c2f4c ./js/ripemd160.js
114089ef2a3feb6d4db4f9cabcb186d7750d5884 ./js/sha512.js
3ff26f7ca616b01742a25f9aa304bdb653ce4a4d ./js/coin.js
cb26a4ae2216754f3089daaf7605e3ac41410126 ./js/coinbin.js
ae49e56999d82802727455f0ba83b63acd90a22b ./js/jquery-1.9.1.min.js
5f570018ed044eafd464f7e0ab1783b966224055 ./LICENCE
506c40035e0d22560478629434d0fea27643b77a ./js/transition.js
5f570018ed044eafd464f7e0ab1783b966224055 ./LICENSE
255c58c17e63eb54adb3cd02b5c06224c67fc364 ./css/bootstrap-datetimepicker.min.css
ed29315e0ffb3f14382431f2724235bf67f44eb3 ./css/bootstrap.min.css
fc6b4268fbd57ad95d2b41a1d4d6866f222fbdb2 ./css/bootstrap-theme.min.css
8297b8f4d686ec6c65981077514975e06ce41812 ./css/style.css
4198ed869836ea5727ad6b80bf2df0a9c1a83244 ./css/style.css
8ac24915d59cef71c542e7cb7d7e153f560cba1f ./images/coinbin.gif
f2af060f1cadbc9065c8c465c648dc01be67cc12 ./images/loader.gif
86b6f62b7853e67d3e635f6512a5a5efc58ea3c3 ./fonts/glyphicons-halflings-regular.eot
@@ -24,5 +29,5 @@ ca35b697d99cae4d1b60f2d60fcd37771987eb07 ./fonts/glyphicons-halflings-regular.w
de51a8494180a6db074af2dee2383f0a363c5b08 ./fonts/glyphicons-halflings-regular.svg
278e49a86e634da6f2a02f3b47dd9d2a8f26210f ./fonts/glyphicons-halflings-regular.woff
44bc1850f570972267b169ae18f1cb06b611ffa2 ./fonts/glyphicons-halflings-regular.ttf
fe8d57914bb036ab94e86ec35b2671eeb6d20d0d ./README.md
f4803ce0396b7e65d2f9dd4a5ae232b32403ef19 ./index.html
d8a324a13501cd5705dc26b945fc8088f00907ae ./README.md
da6e4cbb4a168a3583086e0997c8c678a7a80925 ./index.html