148 Commits

Author SHA1 Message Date
OutCast3k 44ba1b3d30 update readme 2019-12-25 22:15:55 +00:00
OutCast3k 5583675390 custom hd key derivation addded 2019-12-25 22:10:55 +00:00
OutCast3k 56cb104ea4 updated sha1sum 2019-12-24 23:01:50 +00:00
OutCast3k c6f70d000e Merge pull request #194 from jmacxx/fix_issue_140
fix Issue 140: error logged to console when switching tabs.
2019-12-24 23:00:22 +00:00
OutCast3k 4836b20fae updated sha1sum 2019-12-24 22:47:28 +00:00
OutCast3k f364ae4b4a Merge pull request #198 from jmacxx/fix_issue_193
fix: RBF always set when redeeming OP_CHECKLOCKTIMEVERIFY
2019-12-24 22:44:43 +00:00
OutCast3k 64cb387247 updated as outcast3k 2019-12-24 21:53:20 +00:00
btc b2a86006cf updated sha1sum file 2019-12-24 21:51:33 +00:00
OutCast3k b5ebaafed8 Merge pull request #202 from junderw/fixScriptNum
Fix script num
2019-12-24 21:49:03 +00:00
kinoshitajona d4f47fce28 Must do OPs with script method 2019-11-14 15:13:51 +09:00
kinoshitajona 5bd3786f94 Fix ScriptNum 2019-11-14 15:07:15 +09:00
Wowee0 b77f3cf06a fix: RBF always set when redeeming OP_CHECKLOCKTIMEVERIFY 2019-10-18 23:19:52 -05:00
Wowee0 b0c6c3a516 fix Uncaught TypeError logged to console when switching Tx Input and Output tabs 2019-09-23 21:01:03 -05:00
OutCast3k a6f5dcf7f0 removed debugger code 2019-09-22 20:32:42 +00:00
OutCast3k cf2a8b01cb update sha1sum file 2019-08-30 17:03:31 +00:00
OutCast3k 261c4ace40 Merge pull request #191 from Wowee0/choose_backend
fix for #189 .. three backend API options for btc/ltc/doge
2019-08-30 17:58:50 +01:00
Wowee0 e18b634c4e fix issue where empty broadcast did not handle the error response appropriately 2019-08-27 11:17:08 -05:00
Wowee0 1f3b878d63 bugfix for blockcypher when address used that has no UTXO 2019-08-22 07:41:36 -05:00
Wowee0 efc16c10fb allow backend API choice between blockcypher/blockchair/chain.so 2019-08-16 16:28:29 -05:00
Wowee0 477ca8890d Merge pull request #1 from OutCast3k/master
sync with OutCast3k/coinbin
2019-06-15 09:18:15 -05:00
OutCast3k e73e8093b3 change made to avoid captcha provided by cloudflare to TOR users 2019-06-05 19:34:45 +00:00
OutCast3k 40ea3230fd removed blockchain.com links 2019-05-28 15:21:58 +00:00
OutCast3k dc416c6521 changes made to paper wallet 2019-05-24 14:44:47 +00:00
OutCast3k fc66bc9423 Merge pull request #127 from olivergregorius/paperwallet
Paperwallet
2019-05-24 15:41:54 +01:00
OutCast3k 1c10bef510 Merge pull request #183 from yottalogical/blockchain-explorer-link
Add Link to Blockchain Explorer after Broadcasting Transaction (Litecoin)
2019-05-06 11:49:48 +01:00
yottalogical b22e79391f Update sha1sum 2019-05-05 12:36:32 -04:00
yottalogical 0be8fd9a97 Add link to blockchain explorer for Chain.so (Litecoin) 2019-05-05 12:30:28 -04:00
OutCast3k 1a364ff770 updated sha1sum file 2019-05-05 09:22:52 +00:00
OutCast3k bc0c72117e Merge pull request #182 from Wowee0/litecoin
re-enabled Litecoin
2019-05-05 10:11:31 +01:00
OutCast3k 13c50cf4b6 Merge pull request #170 from ivy-dong/ivy_remove_redundant_quotation_marks
remove redundant quotation marks
2019-05-05 10:09:08 +01:00
OutCast3k dea1d1b274 Merge pull request #178 from yottalogical/blockchain-explorer-link 2019-05-05 10:07:00 +01:00
Wowee0 e6c70d133b set appropriate hrp for Litecoin SegWit addresses
set chain.so/address/LTC for view of address (previously was referencing BTC block explorer)
2019-04-22 22:09:20 -05:00
Wowee0 10aa011c6e LTC SegWit (pre-bech32) address version changed from 5 to 50 (i.e. 3-addresses changed to M-addresses) 2019-04-20 23:28:40 -05:00
Wowee0 c7a0fda7e5 re-enabled Litecoin 2019-04-19 10:40:59 -05:00
yottalogical c9cfeefc86 Correct month in sha1sum 2019-02-22 18:19:35 -05:00
yottalogical cdf4aa105b Fix variable name in broadcast success message 2019-02-06 15:43:23 -05:00
yottalogical 2fc574dde0 Remove unnecessary linebreak at end 2019-02-06 15:34:25 -05:00
yottalogical f088ec2e52 Update sha1sum 2019-02-06 15:28:04 -05:00
yottalogical 9ccd73808d Capitalize TXID in success message 2019-02-06 15:23:09 -05:00
yottalogical cb81362330 Add link to blockchain explorer for Cryptoid.info (Carboncoin) 2019-02-06 15:21:39 -05:00
yottalogical fcbf25eaec Add link to blockchain explorer for coinb.in (Bitcoin) 2019-02-06 15:20:43 -05:00
yottalogical 2aca9ab28d Add link to blockchain explorer for Blockcypher.com 2019-02-06 14:46:19 -05:00
yottalogical 5c581316fe Add link to blockchain explorer for Chain.so (Bitcoin) 2019-02-06 14:39:48 -05:00
yottalogical ebfb940dd5 Fix typo in comment 2019-02-06 14:32:49 -05:00
yottalogical 3201550d40 Add link to blockchain explorer for Chain.so (Dogecoin) 2019-02-06 14:23:27 -05:00
OutCast3k d88ec3db4b update sha1sum file 2018-12-28 23:49:01 +00:00
OutCast3k 530453a701 improvement to previous timelock address bug fix 2018-12-28 23:42:00 +00:00
OutCast3k 194df37d56 bug fix for time locked addresses. transactions not being built correctly (no loss of funds!!!!) 2018-12-28 23:33:42 +00:00
Ivy Dong 87461b58b8 remove redundant quotation marks 2018-12-16 20:04:27 +08:00
OutCast3k 739aee3c0f couple of bug fixes with transaction building 2018-08-26 20:53:25 +00:00
OutCast3k fd81fafdff segwit signing bug fix 2018-06-19 15:45:21 +00:00
OutCast3k 9bede2aef4 Update sha1sum 2018-06-17 11:37:21 +01:00
OutCast3k 37f4395d9f wallet segwit spend bugfix 2018-06-17 09:22:44 +00:00
OutCast3k 5a65a77bd2 added a bech32 address to the #wallet section of coinb.in 2018-06-11 16:23:18 +00:00
OutCast3k 734e6b2eeb removed some coded that was no longer needed 2018-05-27 12:10:49 +00:00
OutCast3k 90a309d4b4 first stage of adding bech32 support added to coinb.in 2018-05-27 11:49:09 +00:00
OutCast3k abd2191c50 updated readme 2018-01-15 19:05:45 +00:00
OutCast3k bb8abb4ded some changes and bug fixes to the fees page 2018-01-15 18:58:17 +00:00
OutCast3k 40d514e0f0 couple of minor updates 2018-01-11 16:54:27 +00:00
OutCast3k c3b1a47199 few minor changes, plus the wallet now enables rbf by default 2018-01-06 16:11:20 +00:00
OutCast3k ed7d5d6411 small bugfix so that the #wallet inputs/outputs are properly set on the #fees page 2018-01-04 10:42:45 +00:00
OutCast3k 10e083bd89 add css changes 2018-01-03 19:30:36 +00:00
OutCast3k 56fa7b5139 various tweaks made to the #fees page 2018-01-03 19:27:53 +00:00
OutCast3k e85276dd89 added css changes 2018-01-01 18:58:33 +00:00
OutCast3k c843685662 added new #fee section to coinb.in 2018-01-01 18:53:23 +00:00
OutCast3k 64af126bc5 added segwit redeemscript to wallet, fixed typo, added links 2017-12-09 09:56:06 +00:00
oliverdorn b997751791 Added functionality for printing Paper Wallet 2017-11-25 00:53:00 +01:00
oliverdorn 9bccc5c512 Added Buttons for printing Paper Wallets
Added Buttons for printint Paper Wallets for generated Legacy- and SegWit-Adresses
2017-11-25 00:49:16 +01:00
OutCast3k 217897285e bug fix for issue #118 (do not generate a multisig address when the redeemscript is too large >520bytes) 2017-10-04 08:35:51 +00:00
OutCast3k b1603821da at the risk of upsetting some users segwit addresses have now been enabled by default in the #wallet section, with the option to switch between legacy and segwit very easily. 2017-10-01 18:06:57 +00:00
btc c2ef949dd0 segwit spending bug fixes 2017-09-21 13:38:48 +00:00
btc ecb18acb0f code was missing for the segwit feature from the #wallet section 2017-09-20 09:56:20 +00:00
OutCast3k 4a4f302fe6 added segwit support to the wallet section of #coinb.in 2017-09-16 09:03:10 +00:00
OutCast3k 4afee020b0 Update sha1sum
updated sha1sum
2017-09-12 06:25:00 +01:00
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
12 changed files with 2984 additions and 294 deletions
+7 -2
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.5 beta by OutCast3k
Live version available at http://coinb.in/ or http://4zpinp6gdkjfplhk.onion
@@ -26,5 +26,10 @@ 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
- Bech32 address support
- Fee calculator - https://coinb.in/#fees
Donate to 1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg to see more development!
Donate to 3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN to see more development!
File diff suppressed because one or more lines are too long
+94
View File
@@ -24,3 +24,97 @@ body {
background-color: #f5f5f5;
padding-top: 20px;
}
.alert {
overflow: hidden;
-ms-text-overflow: ellipsis;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
display: block;
}
#fees .txi_regular {
background: #d3d3d3;
}
#fees .txi_segwit {
background: #bae1ff;
}
#fees .txi_multisig {
background: #baffc9;
}
#fees .txi_hodl {
background: #ffdfba;
}
#fees .txi_unknown {
background: #ffb3ba;
}
#fees .txo_p2pkh {
background: #E679C8;
}
#fees .txo_p2sh {
background: #FAFE92;
}
#fees .txinputs {
}
#fees .txoutputs {
}
.hideOverflow {
overflow:hidden;
white-space:nowrap;
text-overflow:ellipsis;
}
#fees .slider {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 30px;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
border: 2px dotted #c3c3c3;
}
#fees .sliderbtn {
height: 30px;
width: 30px;
padding: 0px;
margin: 0px;
border: 0px;
}
#fees .slider:hover {
opacity: 1;
}
#fees .slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 32px;
height: 32px;
border: 0;
background: url('https://coinb.in/images/btc32x.png');
cursor: pointer;
}
#fees .slider::-moz-range-thumb {
width: 32px;
height: 32px;
border: 0;
background: url('https://coinb.in/images/btc32x.png');
cursor: pointer;
}
#fees .total {
font-size: 100px;
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+686 -33
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+643 -51
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
*/
@@ -14,14 +14,16 @@
coinjs.priv = 0x80;
coinjs.multisig = 0x05;
coinjs.hdkey = {'prv':0x0488ade4, 'pub':0x0488b21e};
coinjs.bech32 = {'charset':'qpzry9x8gf2tvdw0s3jn54khce6mua7l', 'version':0, 'hrp':'bc'};
coinjs.compressed = false;
/* other vars */
coinjs.developer = '1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg'; // bitcoin
coinjs.developer = '3K1oFZMks41C7qDYBsr72SYjapLqDuSYuN'; //bitcoin
/* bit(coinb.in) api vars */
coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+'coinb.in/api/';
coinjs.hostname = ((document.location.hostname.split(".")[(document.location.hostname.split(".")).length-1]) == 'onion') ? '4zpinp6gdkjfplhk.onion' : 'coinb.in';
coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+coinjs.hostname+'/api/';
coinjs.uid = '1';
coinjs.key = '12345678901234567890123456789012';
@@ -98,9 +100,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));
@@ -132,9 +134,80 @@
var checksum = r.slice(0,4);
var redeemScript = Crypto.util.bytesToHex(s.buffer);
var address = coinjs.base58encode(x.concat(checksum));
if(s.buffer.length > 520){ // too large
address = 'invalid';
redeemScript = 'invalid';
}
return {'address':address, 'redeemScript':redeemScript, 'size': s.buffer.length};
}
/* 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();
if (checklocktimeverify <= 16 && checklocktimeverify >= 1) {
s.writeOp(0x50 + checklocktimeverify);//OP_1 to OP_16 for minimal encoding
} else {
s.writeBytes(coinjs.numToScriptNumBytes(checklocktimeverify));
}
s.writeOp(177);//OP_CHECKLOCKTIMEVERIFY
s.writeOp(117);//OP_DROP
s.writeBytes(Crypto.util.hexToBytes(pubkey));
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)};
}
/* create a new segwit bech32 encoded address */
coinjs.bech32Address = function(pubkey){
var program = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubkey), {asBytes: true}), {asBytes: true});
var address = coinjs.bech32_encode(coinjs.bech32.hrp, [coinjs.bech32.version].concat(coinjs.bech32_convert(program, 8, 5, true)));
return {'address':address, 'type':'bech32', 'redeemscript':Crypto.util.bytesToHex(program)};
}
/* extract the redeemscript from a bech32 address */
coinjs.bech32redeemscript = function(address){
var r = false;
var decode = coinjs.bech32_decode(address);
if(decode){
decode.data.shift();
return Crypto.util.bytesToHex(coinjs.bech32_convert(decode.data, 5, 8, true));
}
return r;
}
/* provide a privkey and return an WIF */
coinjs.privkey2wif = function(h){
var r = Crypto.util.hexToBytes(h);
@@ -237,9 +310,14 @@
return false;
}
} catch(e) {
bech32rs = coinjs.bech32redeemscript(addr);
if(bech32rs){
return {'type':'bech32', 'redeemscript':bech32rs};
} else {
return false;
}
}
}
/* retreive the balance from a given address */
coinjs.addressBalance = function(address, callback){
@@ -248,6 +326,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 +342,128 @@
return false;
}
}
return false;
}
coinjs.bech32_polymod = function(values) {
var chk = 1;
var BECH32_GENERATOR = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
for (var p = 0; p < values.length; ++p) {
var top = chk >> 25;
chk = (chk & 0x1ffffff) << 5 ^ values[p];
for (var i = 0; i < 5; ++i) {
if ((top >> i) & 1) {
chk ^= BECH32_GENERATOR[i];
}
}
}
return chk;
}
coinjs.bech32_hrpExpand = function(hrp) {
var ret = [];
var p;
for (p = 0; p < hrp.length; ++p) {
ret.push(hrp.charCodeAt(p) >> 5);
}
ret.push(0);
for (p = 0; p < hrp.length; ++p) {
ret.push(hrp.charCodeAt(p) & 31);
}
return ret;
}
coinjs. bech32_verifyChecksum = function(hrp, data) {
return coinjs.bech32_polymod(coinjs.bech32_hrpExpand(hrp).concat(data)) === 1;
}
coinjs.bech32_createChecksum = function(hrp, data) {
var values = coinjs.bech32_hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
var mod = coinjs.bech32_polymod(values) ^ 1;
var ret = [];
for (var p = 0; p < 6; ++p) {
ret.push((mod >> 5 * (5 - p)) & 31);
}
return ret;
}
coinjs.bech32_encode = function(hrp, data) {
var combined = data.concat(coinjs.bech32_createChecksum(hrp, data));
var ret = hrp + '1';
for (var p = 0; p < combined.length; ++p) {
ret += coinjs.bech32.charset.charAt(combined[p]);
}
return ret;
}
coinjs.bech32_decode = function(bechString) {
var p;
var has_lower = false;
var has_upper = false;
for (p = 0; p < bechString.length; ++p) {
if (bechString.charCodeAt(p) < 33 || bechString.charCodeAt(p) > 126) {
return null;
}
if (bechString.charCodeAt(p) >= 97 && bechString.charCodeAt(p) <= 122) {
has_lower = true;
}
if (bechString.charCodeAt(p) >= 65 && bechString.charCodeAt(p) <= 90) {
has_upper = true;
}
}
if (has_lower && has_upper) {
return null;
}
bechString = bechString.toLowerCase();
var pos = bechString.lastIndexOf('1');
if (pos < 1 || pos + 7 > bechString.length || bechString.length > 90) {
return null;
}
var hrp = bechString.substring(0, pos);
var data = [];
for (p = pos + 1; p < bechString.length; ++p) {
var d = coinjs.bech32.charset.indexOf(bechString.charAt(p));
if (d === -1) {
return null;
}
data.push(d);
}
if (!coinjs.bech32_verifyChecksum(hrp, data)) {
return null;
}
return {
hrp: hrp,
data: data.slice(0, data.length - 6)
};
}
coinjs.bech32_convert = function(data, inBits, outBits, pad) {
var value = 0;
var bits = 0;
var maxV = (1 << outBits) - 1;
var result = [];
for (var i = 0; i < data.length; ++i) {
value = (value << inBits) | data[i];
bits += inBits;
while (bits >= outBits) {
bits -= outBits;
result.push((value >> bits) & maxV);
}
}
if (pad) {
if (bits > 0) {
result.push((value << (outBits - bits)) & maxV);
}
} else {
if (bits >= inBits) throw new Error('Excess padding');
if ((value << (outBits - bits)) & maxV) throw new Error('Non-zero padding');
}
return result;
}
coinjs.testdeterministicK = function() {
// https://github.com/bitpay/bitcore/blob/9a5193d8e94b0bd5b8e7f00038e7c0b935405a03/test/crypto/ecdsa.js
@@ -437,6 +638,8 @@
coinjs.compressed = c; // reset to default
}
return r;
}
// extend prv/pub key
@@ -450,8 +653,37 @@
'pubkey':this.keys.pubkey});
}
// derive from path
r.derive_path = function(path) {
if( path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'' ) return this;
var p = path.split('/');
var hdp = coinjs.clone(this); // clone hd path
for( var i in p ) {
if((( i == 0 ) && c != 'm') || i == 'remove'){
continue;
}
var c = p[i];
var use_private = (c.length > 1) && (c[c.length-1] == '\'');
var child_index = parseInt(use_private ? c.slice(0, c.length - 1) : c) & 0x7fffffff;
if(use_private)
child_index += 0x80000000;
hdp = hdp.derive(child_index);
var key = ((hdp.keys_extended.privkey) && hdp.keys_extended.privkey!='') ? hdp.keys_extended.privkey : hdp.keys_extended.pubkey;
hdp = coinjs.hd(key);
}
return hdp;
}
// derive key from index
r.derive = function(i){
i = (i)?i:0;
var blob = (Crypto.util.hexToBytes(this.keys.pubkey)).concat(coinjs.numToBytes(i,4).reverse());
@@ -506,7 +738,6 @@
o.parent_fingerprint = (ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(r.keys.pubkey),{asBytes:true}),{asBytes:true})).slice(0,4);
o.keys_extended = o.extend();
return o;
}
@@ -571,8 +802,7 @@
return o;
}
r.parse();
return r;
return r.parse();
}
@@ -587,7 +817,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 +879,26 @@
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"
var rs = Crypto.util.bytesToHex(s.buffer);
r.redeemscript = rs;
} else if((s.chunks.length==2) && (s.buffer[0] == 0 && s.buffer[1] == 20)){ // SEGWIT
r = {};
r.type = "segwit__";
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;
var rs = Crypto.util.bytesToHex(s.buffer);
r.redeemscript = rs;
r.type = "hodl__";
}
} catch(e) {
// console.log(e);
@@ -661,7 +911,10 @@
r.spendToScript = function(address){
var addr = coinjs.addressDecode(address);
var s = coinjs.script();
if(addr.version==5){ // multisig address
if(addr.type == "bech32"){
s.writeOp(0);
s.writeBytes(Crypto.util.hexToBytes(addr.redeemscript));
} else if(addr.version==coinjs.multisig){ // multisig address
s.writeOp(169); //OP_HASH160
s.writeBytes(addr.bytes);
s.writeOp(135); //OP_EQUAL
@@ -731,15 +984,16 @@
r.lock_time = 0;
r.ins = [];
r.outs = [];
r.witness = false;
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 +1050,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));
@@ -814,11 +1068,10 @@
}
/* add unspent to transaction */
r.addUnspent = function(address, callback){
r.addUnspent = function(address, callback, script, segwit, sequence){
var self = this;
this.listUnspent(address, function(data){
var s = coinjs.script();
var pubkeyScript = s.pubkeyHash(address);
var value = 0;
var total = 0;
var x = {};
@@ -838,10 +1091,21 @@
var u = xmlDoc.getElementsByTagName("unspent_"+i)[0]
var txhash = (u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue).match(/.{1,2}/g).reverse().join("")+'';
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
var script = u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
self.addinput(txhash, n, script);
if(segwit){
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
It is not standard and removed during the signing procedure. */
s = coinjs.script();
s.writeBytes(Crypto.util.hexToBytes(script));
s.writeOp(0);
s.writeBytes(coinjs.numToBytes(u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1, 8));
scr = Crypto.util.bytesToHex(s.buffer);
}
var seq = sequence || false;
self.addinput(txhash, n, scr, seq);
value += u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1;
total++;
}
@@ -870,9 +1134,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 +1149,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 +1213,127 @@
}
}
/* 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'};
}
if(extract['value'] == -1){
return {'result':0, 'fail':'value', 'response':'unable to generate a valid segwit hash without a value'};
}
var scriptcode = Crypto.util.hexToBytes(extract['script']);
// end of redeem script check
/* P2WPKH */
if(scriptcode.length == 20){
scriptcode = [0x00,0x14].concat(scriptcode);
}
if(scriptcode.length == 22){
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) || (this.ins[index].script.chunks[0].length == 20 && this.ins[index].script.chunks[1] == 0))){
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 +1353,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 +1374,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 +1400,7 @@
};
var sig = serializeSig(r, s);
sig.push(parseInt(1, 10));
sig.push(parseInt(shType, 10));
return Crypto.util.bytesToHex(sig);
} else {
@@ -995,12 +1429,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 +1471,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 +1482,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 +1507,118 @@
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']);
var bech32 = coinjs.bech32Address(wif2['pubkey']);
if((segwit['redeemscript'] == Crypto.util.bytesToHex(this.ins[index].script.chunks[0])) || (bech32['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;
if(!coinjs.isArray(this.witness)){
this.witness = [];
}
this.witness.push([signature, wif2['pubkey']]);
/* attempt to reorder witness data as best as we can.
data can't be easily validated at this stage as
we dont have access to the inputs value and
making a web call will be too slow. */
var witness_order = [];
var witness_used = [];
for(var i = 0; i < this.ins.length; i++){
for(var y = 0; y < this.witness.length; y++){
if(!witness_used.includes(y)){
var sw = coinjs.segwitAddress(this.witness[y][1]);
var b32 = coinjs.bech32Address(this.witness[y][1]);
var rs = '';
if(this.ins[i].script.chunks.length>=1){
rs = Crypto.util.bytesToHex(this.ins[i].script.chunks[0]);
} else if (this.ins[i].script.chunks.length==0){
rs = b32['redeemscript'];
}
if((sw['redeemscript'] == rs) || (b32['redeemscript'] == rs)){
witness_order.push(this.witness[y]);
witness_used.push(y);
// bech32, empty redeemscript
if(b32['redeemscript'] == rs){
this.ins[index].script = coinjs.script();
}
break;
}
}
}
}
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 +1627,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 +1649,12 @@
r.serialize = function(){
var buffer = [];
buffer = buffer.concat(coinjs.numToBytes(parseInt(this.version),4));
buffer = buffer.concat(coinjs.numToVarInt(this.ins.length));
if(coinjs.isArray(this.witness)){
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 +1674,16 @@
buffer = buffer.concat(scriptBytes);
}
if((coinjs.isArray(this.witness)) && 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 +1695,8 @@
}
var pos = 0;
var witness = false;
var readAsInt = function(bytes) {
if (bytes == 0) return 0;
pos++;
@@ -1181,8 +1722,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 +1751,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 +1936,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 +1947,43 @@
}
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));
}
}
function scriptNumSize(i) {
return i > 0x7fffffff ? 5
: i > 0x7fffff ? 4
: i > 0x7fff ? 3
: i > 0x7f ? 2
: i > 0x00 ? 1
: 0;
}
coinjs.numToScriptNumBytes = function(_number) {
var value = Math.abs(_number);
var size = scriptNumSize(value);
var result = [];
for (var i = 0; i < size; ++i) {
result.push(0);
}
var negative = _number < 0;
for (i = 0; i < size; ++i) {
result[i] = value & 0xff;
value = Math.floor(value / 256);
}
if (negative) {
result[size - 1] |= 0x80;
}
return result;
}
coinjs.numToVarInt = function(num) {
if (num < 253) {
return [num];
@@ -1400,7 +1992,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));
}
}
+1161 -112
View File
File diff suppressed because it is too large Load Diff
+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);
+19 -13
View File
@@ -1,22 +1,28 @@
---- Version 1.2 2015.07.23 ----
e6810907c901e6bd34a28735a68850936f0823b8 ./js/ellipticcurve.js
9ba5ede3d7f9d4c8fd623395f196adfdcf7e970f ./js/crypto-min.js
---- Version 1.4 2019.12.25 ----
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
17cc6a56ee601fbe3858563f26232f64ce12abcb ./js/coinbin.js
dc83017470f3ced2b0d522781b3ccded0d3a8d28 ./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
eb54f374256b75a17f274847b4ca9985fd046f9f ./css/style.css
2e3217a3f3b7c2fb30562ab9a4ef9a407ae81897 ./images/btc32x.png
8ac24915d59cef71c542e7cb7d7e153f560cba1f ./images/coinbin.gif
f2af060f1cadbc9065c8c465c648dc01be67cc12 ./images/loader.gif
86b6f62b7853e67d3e635f6512a5a5efc58ea3c3 ./fonts/glyphicons-halflings-regular.eot
@@ -24,5 +30,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
4665ee4d8ca96db25954f6f3587ac367386eb9e8 ./README.md
9cf7084c331b7c536f5f6e34533300c3d9d3e038 ./index.html