2014-12-02 00:36:49 +01:00
$ ( document ) . ready ( function ( ) {
/* open wallet code */
$ ( "#openBtn" ) . click ( function ( ) {
var email = $ ( "#openEmail" ) . val ( ) . toLowerCase ( ) ;
if ( email . match ( /[\s\w\d]+@[\s\w\d]+/g ) ) {
if ( $ ( "#openPass" ) . val ( ) . length >= 10 ) {
if ( $ ( "#openPass" ) . val ( ) == $ ( "#openPassConfirm" ) . val ( ) ) {
var email = $ ( "#openEmail" ) . val ( ) . toLowerCase ( ) ;
var pass = $ ( "#openPass" ) . val ( ) ;
var s = email ;
s += '|' + pass + '|' ;
s += s . length + '|!@' + ( ( pass . length * 7 ) + email . length ) * 7 ;
var regchars = ( pass . match ( /[a-z]+/g ) ) ? pass . match ( /[a-z]+/g ) . length : 1 ;
var regupchars = ( pass . match ( /[A-Z]+/g ) ) ? pass . match ( /[A-Z]+/g ) . length : 1 ;
var regnums = ( pass . match ( /[0-9]+/g ) ) ? pass . match ( /[0-9]+/g ) . length : 1 ;
s += ( ( regnums + regchars ) + regupchars ) * pass . length + '3571' ;
2014-12-05 14:27:28 +01:00
s += ( s + '' + s ) ;
2014-12-02 00:36:49 +01:00
for ( i = 0 ; i <= 50 ; i ++ ) {
s = Crypto . SHA256 ( s ) ;
}
coinjs . compressed = true ;
var keys = coinjs . newKeys ( s ) ;
$ ( "#walletAddress" ) . html ( keys . address ) ;
2014-12-07 19:05:55 +01:00
$ ( "#walletHistory" ) . attr ( 'href' , 'https://btc.blockr.io/address/info/' + keys . address ) ;
2014-12-07 19:01:08 +01:00
2014-12-07 20:12:52 +01:00
$ ( "#walletQrCode" ) . html ( "" ) ;
2014-12-07 19:01:08 +01:00
var qrcode = new QRCode ( "walletQrCode" ) ;
qrcode . makeCode ( "bitcoin:" + keys . address ) ;
2014-12-02 00:36:49 +01:00
$ ( "#walletKeys .privkey" ) . val ( keys . wif ) ;
$ ( "#walletKeys .pubkey" ) . val ( keys . pubkey ) ;
2015-01-09 00:48:58 +01:00
$ ( "#walletKeys .privkeyaes" ) . val ( CryptoJS . AES . encrypt ( keys . wif , pass ) ) ;
2014-12-02 00:36:49 +01:00
$ ( "#openLogin" ) . hide ( ) ;
$ ( "#openWallet" ) . removeClass ( "hidden" ) . show ( ) ;
walletBalance ( ) ;
checkBalanceLoop ( ) ;
} else {
$ ( "#openLoginStatus" ) . html ( "Your passwords do not match!" ) . removeClass ( "hidden" ) . fadeOut ( ) . fadeIn ( ) ;
}
} else {
$ ( "#openLoginStatus" ) . html ( "Your password must be at least 10 chars long" ) . removeClass ( "hidden" ) . fadeOut ( ) . fadeIn ( ) ;
}
} else {
$ ( "#openLoginStatus" ) . html ( "Your email address doesn't appear to be valid" ) . removeClass ( "hidden" ) . fadeOut ( ) . fadeIn ( ) ;
}
$ ( "#openLoginStatus" ) . prepend ( '<span class="glyphicon glyphicon-exclamation-sign"></span> ' ) ;
} ) ;
$ ( "#walletLogout" ) . click ( function ( ) {
$ ( "#openEmail" ) . val ( "" ) ;
$ ( "#openPass" ) . val ( "" ) ;
$ ( "#openPassConfirm" ) . val ( "" ) ;
$ ( "#openLogin" ) . show ( ) ;
$ ( "#openWallet" ) . addClass ( "hidden" ) . show ( ) ;
$ ( "#walletAddress" ) . html ( "" ) ;
2014-12-07 19:05:55 +01:00
$ ( "#walletHistory" ) . attr ( 'href' , 'https://btc.blockr.io/address/info/' ) ;
2014-12-07 19:01:08 +01:00
2014-12-07 20:12:52 +01:00
$ ( "#walletQrCode" ) . html ( "" ) ;
2014-12-07 19:01:08 +01:00
var qrcode = new QRCode ( "walletQrCode" ) ;
qrcode . makeCode ( "bitcoin:" ) ;
2014-12-02 00:36:49 +01:00
$ ( "#walletKeys .privkey" ) . val ( "" ) ;
$ ( "#walletKeys .pubkey" ) . val ( "" ) ;
} ) ;
$ ( "#walletShowKeys" ) . click ( function ( ) {
$ ( "#walletKeys" ) . removeClass ( "hidden" ) ;
$ ( "#walletSpend" ) . removeClass ( "hidden" ) . addClass ( "hidden" ) ;
} ) ;
$ ( "#walletBalance" ) . click ( function ( ) {
walletBalance ( ) ;
} ) ;
$ ( "#walletConfirmSend" ) . click ( function ( ) {
var thisbtn = $ ( this ) ;
var tx = coinjs . transaction ( ) ;
var txfee = $ ( "#txFee" ) ;
var devaddr = coinjs . developer ;
var devamount = $ ( "#developerDonation" ) ;
if ( ( devamount . val ( ) * 1 ) > 0 ) {
tx . addoutput ( devaddr , devamount . val ( ) * 1 ) ;
}
var total = ( devamount . val ( ) * 1 ) + ( txfee . val ( ) * 1 ) ;
$ . each ( $ ( "#walletSpendTo .output" ) , function ( i , o ) {
var addr = $ ( '.addressTo' , o ) ;
var amount = $ ( '.amount' , o ) ;
2016-07-29 00:36:27 +02:00
if ( amount . val ( ) * 1 > 0 ) {
total += amount . val ( ) * 1 ;
tx . addoutput ( addr . val ( ) , amount . val ( ) * 1 ) ;
}
2014-12-02 00:36:49 +01:00
} ) ;
thisbtn . attr ( 'disabled' , true ) ;
tx . addUnspent ( $ ( "#walletAddress" ) . html ( ) , function ( data ) {
2016-07-29 00:36:27 +02:00
var dvalue = ( data . value / 100000000 ) . toFixed ( 8 ) ;
total = total . toFixed ( 8 ) ;
2014-12-02 00:36:49 +01:00
if ( dvalue >= total ) {
var change = dvalue - total ;
2016-07-29 00:36:27 +02:00
if ( ( change * 1 ) > 0 ) {
2014-12-02 00:36:49 +01:00
tx . addoutput ( $ ( "#walletAddress" ) . html ( ) , change ) ;
}
// clone the transaction with out using coinjs.clone() function as it gives us trouble
var tx2 = coinjs . transaction ( ) ;
var txunspent = tx2 . deserialize ( tx . serialize ( ) ) ;
// then sign
var signed = txunspent . sign ( $ ( "#walletKeys .privkey" ) . val ( ) ) ;
// and finally broadcast!
tx2 . broadcast ( function ( data ) {
if ( $ ( data ) . find ( "result" ) . text ( ) == "1" ) {
$ ( "#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 , ' ' ) ) ;
2016-02-10 00:52:55 +01:00
$ ( "#walletSendFailTransaction" ) . removeClass ( 'hidden' ) ;
$ ( "#walletSendFailTransaction textarea" ) . val ( signed ) ;
2015-09-12 20:38:34 +02:00
thisbtn . attr ( 'disabled' , false ) ;
2014-12-02 00:36:49 +01:00
}
// update wallet balance
walletBalance ( ) ;
} , 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 ( ) ;
2015-09-12 20:38:34 +02:00
thisbtn . attr ( 'disabled' , false ) ;
2014-12-02 00:36:49 +01:00
}
$ ( "#walletLoader" ) . addClass ( "hidden" ) ;
} ) ;
} ) ;
$ ( "#walletSendBtn" ) . click ( function ( ) {
2016-02-10 00:52:55 +01:00
$ ( "#walletSendFailTransaction" ) . addClass ( 'hidden' ) ;
2014-12-02 00:36:49 +01:00
$ ( "#walletSendStatus" ) . addClass ( "hidden" ) . html ( "" ) ;
var thisbtn = $ ( this ) ;
var txfee = $ ( "#txFee" ) ;
var devamount = $ ( "#developerDonation" ) ;
if ( ( ! isNaN ( devamount . val ( ) ) ) && devamount . val ( ) >= 0 ) {
$ ( devamount ) . parent ( ) . removeClass ( 'has-error' ) ;
} else {
$ ( devamount ) . parent ( ) . addClass ( 'has-error' )
}
if ( ( ! isNaN ( txfee . val ( ) ) ) && txfee . val ( ) >= 0 ) {
$ ( txfee ) . parent ( ) . removeClass ( 'has-error' ) ;
} else {
$ ( txfee ) . parent ( ) . addClass ( 'has-error' ) ;
}
var total = ( devamount . val ( ) * 1 ) + ( txfee . val ( ) * 1 ) ;
$ . each ( $ ( "#walletSpendTo .output" ) , function ( i , o ) {
var amount = $ ( '.amount' , o ) ;
var address = $ ( '.addressTo' , o ) ;
total += amount . val ( ) * 1 ;
if ( ( ! isNaN ( $ ( amount ) . val ( ) ) ) && $ ( amount ) . val ( ) > 0 ) {
$ ( amount ) . parent ( ) . removeClass ( 'has-error' ) ;
} else {
$ ( amount ) . parent ( ) . addClass ( 'has-error' ) ;
}
if ( coinjs . addressDecode ( $ ( address ) . val ( ) ) ) {
$ ( address ) . parent ( ) . removeClass ( 'has-error' ) ;
} else {
$ ( address ) . parent ( ) . addClass ( 'has-error' ) ;
}
} ) ;
total = total . toFixed ( 8 ) ;
if ( $ ( "#walletSpend .has-error" ) . length == 0 ) {
var balance = ( $ ( "#walletBalance" ) . html ( ) ) . replace ( /[^0-9\.]+/g , '' ) * 1 ;
if ( total <= balance ) {
$ ( "#walletSendConfirmStatus" ) . addClass ( "hidden" ) . removeClass ( 'alert-success' ) . removeClass ( 'alert-danger' ) . html ( "" ) ;
$ ( "#spendAmount" ) . html ( total ) ;
$ ( "#modalWalletConfirm" ) . modal ( "show" ) ;
$ ( "#walletConfirmSend" ) . attr ( 'disabled' , false ) ;
} else {
$ ( "#walletSendStatus" ) . removeClass ( "hidden" ) . html ( "You are trying to spend " + total + ' but have a balance of ' + balance ) ;
}
} else {
$ ( "#walletSpend .has-error" ) . fadeOut ( ) . fadeIn ( ) ;
$ ( "#walletSendStatus" ) . removeClass ( "hidden" ) . html ( '<span class="glyphicon glyphicon-exclamation-sign"></span> One or more input has an error' ) ;
}
} ) ;
$ ( "#walletShowSpend" ) . click ( function ( ) {
$ ( "#walletSpend" ) . removeClass ( "hidden" ) ;
$ ( "#walletKeys" ) . removeClass ( "hidden" ) . addClass ( "hidden" ) ;
} ) ;
$ ( "#walletSpendTo .addressAdd" ) . click ( function ( ) {
2015-03-24 01:40:56 +01:00
var clone = '<div class="form-horizontal output">' + $ ( this ) . parent ( ) . html ( ) + '</div>' ;
2014-12-02 00:36:49 +01:00
$ ( "#walletSpendTo" ) . append ( clone ) ;
$ ( "#walletSpendTo .glyphicon-plus:last" ) . removeClass ( 'glyphicon-plus' ) . addClass ( 'glyphicon-minus' ) ;
$ ( "#walletSpendTo .glyphicon-minus:last" ) . parent ( ) . removeClass ( 'addressAdd' ) . addClass ( 'addressRemove' ) ;
$ ( "#walletSpendTo .addressRemove" ) . unbind ( "" ) ;
$ ( "#walletSpendTo .addressRemove" ) . click ( function ( ) {
$ ( this ) . parent ( ) . fadeOut ( ) . remove ( ) ;
} ) ;
} ) ;
function walletBalance ( ) {
var tx = coinjs . transaction ( ) ;
$ ( "#walletLoader" ) . removeClass ( "hidden" ) ;
coinjs . addressBalance ( $ ( "#walletAddress" ) . html ( ) , function ( data ) {
if ( $ ( data ) . find ( "result" ) . text ( ) == 1 ) {
var v = $ ( data ) . find ( "balance" ) . text ( ) / 100000000 ;
$ ( "#walletBalance" ) . html ( v + " BTC" ) . attr ( 'rel' , v ) . fadeOut ( ) . fadeIn ( ) ;
} else {
$ ( "#walletBalance" ) . html ( "0.00 BTC" ) . attr ( 'rel' , v ) . fadeOut ( ) . fadeIn ( ) ;
}
$ ( "#walletLoader" ) . addClass ( "hidden" ) ;
} ) ;
}
function checkBalanceLoop ( ) {
setTimeout ( function ( ) {
walletBalance ( ) ;
checkBalanceLoop ( ) ;
} , 45000 ) ;
}
/* new -> address code */
$ ( "#newKeysBtn" ) . click ( function ( ) {
coinjs . compressed = false ;
if ( $ ( "#newCompressed" ) . is ( ":checked" ) ) {
coinjs . compressed = true ;
}
var s = ( $ ( "#newBrainwallet" ) . is ( ":checked" ) ) ? $ ( "#brainwallet" ) . val ( ) : null ;
var coin = coinjs . newKeys ( s ) ;
$ ( "#newBitcoinAddress" ) . val ( coin . address ) ;
$ ( "#newPubKey" ) . val ( coin . pubkey ) ;
$ ( "#newPrivKey" ) . val ( coin . wif ) ;
2015-01-08 23:57:49 +01:00
/* encrypted key code */
if ( ( ! $ ( "#encryptKey" ) . is ( ":checked" ) ) || $ ( "#aes256pass" ) . val ( ) == $ ( "#aes256pass_confirm" ) . val ( ) ) {
$ ( "#aes256passStatus" ) . addClass ( "hidden" ) ;
2015-03-09 13:47:44 +01:00
if ( $ ( "#encryptKey" ) . is ( ":checked" ) ) {
$ ( "#aes256wifkey" ) . removeClass ( "hidden" ) ;
}
2015-01-08 23:57:49 +01:00
} else {
$ ( "#aes256passStatus" ) . removeClass ( "hidden" ) ;
}
$ ( "#newPrivKeyEnc" ) . val ( CryptoJS . AES . encrypt ( coin . wif , $ ( "#aes256pass" ) . val ( ) ) + '' ) ;
2014-12-02 00:36:49 +01:00
} ) ;
$ ( "#newBrainwallet" ) . click ( function ( ) {
if ( $ ( this ) . is ( ":checked" ) ) {
$ ( "#brainwallet" ) . removeClass ( "hidden" ) ;
} else {
$ ( "#brainwallet" ) . addClass ( "hidden" ) ;
}
} ) ;
2015-01-08 23:57:49 +01:00
$ ( "#encryptKey" ) . click ( function ( ) {
if ( $ ( this ) . is ( ":checked" ) ) {
2015-03-09 13:47:44 +01:00
$ ( "#aes256passform" ) . removeClass ( "hidden" ) ;
2015-01-08 23:57:49 +01:00
} else {
2015-03-09 13:47:44 +01:00
$ ( "#aes256wifkey, #aes256passform, #aes256passStatus" ) . addClass ( "hidden" ) ;
2015-01-08 23:57:49 +01:00
}
} ) ;
2014-12-02 00:36:49 +01:00
/* new -> multisig code */
$ ( "#newMultiSigAddress" ) . click ( function ( ) {
$ ( "#multiSigData" ) . removeClass ( 'show' ) . addClass ( 'hidden' ) . fadeOut ( ) ;
$ ( "#multisigPubKeys .pubkey" ) . parent ( ) . removeClass ( 'has-error' ) ;
$ ( "#releaseCoins" ) . parent ( ) . removeClass ( 'has-error' ) ;
$ ( "#multiSigErrorMsg" ) . hide ( ) ;
if ( ( isNaN ( $ ( "#releaseCoins option:selected" ) . html ( ) ) ) || ( ( ! isNaN ( $ ( "#releaseCoins option:selected" ) . html ( ) ) ) && ( $ ( "#releaseCoins option:selected" ) . html ( ) > $ ( "#multisigPubKeys .pubkey" ) . length || $ ( "#releaseCoins option:selected" ) . html ( ) * 1 <= 0 || $ ( "#releaseCoins option:selected" ) . html ( ) * 1 > 8 ) ) ) {
$ ( "#releaseCoins" ) . parent ( ) . addClass ( 'has-error' ) ;
$ ( "#multiSigErrorMsg" ) . html ( '<span class="glyphicon glyphicon-exclamation-sign"></span> Minimum signatures required is greater than the amount of public keys provided' ) . fadeIn ( ) ;
return false ;
}
var keys = [ ] ;
$ . each ( $ ( "#multisigPubKeys .pubkey" ) , function ( i , o ) {
if ( coinjs . pubkeydecompress ( $ ( o ) . val ( ) ) ) {
keys . push ( $ ( o ) . val ( ) ) ;
$ ( o ) . parent ( ) . removeClass ( 'has-error' ) ;
} else {
$ ( o ) . parent ( ) . addClass ( 'has-error' ) ;
}
} ) ;
if ( ( $ ( "#multisigPubKeys .pubkey" ) . parent ( ) . hasClass ( 'has-error' ) == false ) && $ ( "#releaseCoins" ) . parent ( ) . hasClass ( 'has-error' ) == false ) {
var sigsNeeded = $ ( "#releaseCoins option:selected" ) . html ( ) ;
var multisig = coinjs . pubkeys2MultisigAddress ( keys , sigsNeeded ) ;
$ ( "#multiSigData .address" ) . val ( multisig [ 'address' ] ) ;
$ ( "#multiSigData .script" ) . val ( multisig [ 'redeemScript' ] ) ;
2014-12-23 15:25:43 +01:00
$ ( "#multiSigData .scriptUrl" ) . val ( document . location . origin + '' + document . location . pathname + '?verify=' + multisig [ 'redeemScript' ] + '#verify' ) ;
2014-12-02 00:36:49 +01:00
$ ( "#multiSigData" ) . removeClass ( 'hidden' ) . addClass ( 'show' ) . fadeIn ( ) ;
$ ( "#releaseCoins" ) . removeClass ( 'has-error' ) ;
} else {
$ ( "#multiSigErrorMsg" ) . html ( '<span class="glyphicon glyphicon-exclamation-sign"></span> One or more public key is invalid!' ) . fadeIn ( ) ;
}
} ) ;
$ ( "#multisigPubKeys .pubkeyAdd" ) . click ( function ( ) {
if ( $ ( "#multisigPubKeys .pubkeyRemove" ) . length < 14 ) {
2015-03-23 14:02:29 +01:00
var clone = '<div class="form-horizontal">' + $ ( this ) . parent ( ) . html ( ) + '</div>' ;
2014-12-02 00:36:49 +01:00
$ ( "#multisigPubKeys" ) . append ( clone ) ;
$ ( "#multisigPubKeys .glyphicon-plus:last" ) . removeClass ( 'glyphicon-plus' ) . addClass ( 'glyphicon-minus' ) ;
$ ( "#multisigPubKeys .glyphicon-minus:last" ) . parent ( ) . removeClass ( 'pubkeyAdd' ) . addClass ( 'pubkeyRemove' ) ;
$ ( "#multisigPubKeys .pubkeyRemove" ) . unbind ( "" ) ;
$ ( "#multisigPubKeys .pubkeyRemove" ) . click ( function ( ) {
$ ( this ) . parent ( ) . fadeOut ( ) . remove ( ) ;
} ) ;
}
} ) ;
2015-09-12 20:38:34 +02:00
$ ( "#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 ( ) ;
}
} ) ;
2015-12-27 04:37:51 +01:00
/* new -> time locked code */
$ ( '#timeLockedDateTimePicker' ) . datetimepicker ( {
format : "MM/DD/YYYY HH:mm" ,
} ) ;
2016-07-03 19:28:47 +02:00
$ ( '#timeLockedRbTypeBox input' ) . change ( function ( ) {
if ( $ ( '#timeLockedRbTypeDate' ) . is ( ':checked' ) ) {
$ ( '#timeLockedDateTimePicker' ) . show ( ) ;
$ ( '#timeLockedBlockHeight' ) . hide ( ) ;
} else {
$ ( '#timeLockedDateTimePicker' ) . hide ( ) ;
$ ( '#timeLockedBlockHeight' ) . removeClass ( 'hidden' ) . show ( ) ;
}
} ) ;
2015-12-27 04:37:51 +01:00
$ ( "#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' ) ;
}
2016-07-03 19:28:47 +02:00
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' ) ;
}
2015-12-27 04:37:51 +01:00
}
if ( ( $ ( "#timeLockedPubKey" ) . parent ( ) . hasClass ( 'has-error' ) == false ) && $ ( "#timeLockedDateTimePicker" ) . parent ( ) . hasClass ( 'has-error' ) == false ) {
try {
2016-07-03 19:28:47 +02:00
var hodl = coinjs . simpleHodlAddress ( $ ( "#timeLockedPubKey" ) . val ( ) , nLockTime ) ;
2015-12-27 04:37:51 +01:00
$ ( "#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 ( ) ;
}
} ) ;
2015-05-17 02:30:21 +02:00
/* new -> Hd address code */
$ ( ".deriveHDbtn" ) . click ( function ( ) {
$ ( "#verifyScript" ) . val ( $ ( "input[type='text']" , $ ( this ) . parent ( ) . parent ( ) ) . val ( ) ) ;
window . location = "#verify" ;
$ ( "#verifyBtn" ) . click ( ) ;
} ) ;
$ ( "#newHDKeysBtn" ) . click ( function ( ) {
coinjs . compressed = true ;
var s = ( $ ( "#newHDBrainwallet" ) . is ( ":checked" ) ) ? $ ( "#HDBrainwallet" ) . val ( ) : null ;
var hd = coinjs . hd ( ) ;
var pair = hd . master ( s ) ;
$ ( "#newHDxpub" ) . val ( pair . pubkey ) ;
$ ( "#newHDxprv" ) . val ( pair . privkey ) ;
} ) ;
$ ( "#newHDBrainwallet" ) . click ( function ( ) {
if ( $ ( this ) . is ( ":checked" ) ) {
$ ( "#HDBrainwallet" ) . removeClass ( "hidden" ) ;
} else {
$ ( "#HDBrainwallet" ) . addClass ( "hidden" ) ;
}
} ) ;
2014-12-02 00:36:49 +01:00
/* new -> transaction code */
$ ( "#recipients .addressAddTo" ) . click ( function ( ) {
if ( $ ( "#recipients .addressRemoveTo" ) . length < 19 ) {
var clone = '<div class="row recipient"><br>' + $ ( this ) . parent ( ) . parent ( ) . html ( ) + '</div>' ;
$ ( "#recipients" ) . append ( clone ) ;
$ ( "#recipients .glyphicon-plus:last" ) . removeClass ( 'glyphicon-plus' ) . addClass ( 'glyphicon-minus' ) ;
$ ( "#recipients .glyphicon-minus:last" ) . parent ( ) . removeClass ( 'addressAdd' ) . addClass ( 'addressRemoveTo' ) ;
$ ( "#recipients .addressRemoveTo" ) . unbind ( "" ) ;
$ ( "#recipients .addressRemoveTo" ) . click ( function ( ) {
$ ( this ) . parent ( ) . parent ( ) . fadeOut ( ) . remove ( ) ;
validateOutputAmount ( ) ;
} ) ;
validateOutputAmount ( ) ;
}
} ) ;
$ ( "#inputs .txidAdd" ) . click ( function ( ) {
var clone = '<div class="row inputs"><br>' + $ ( this ) . parent ( ) . parent ( ) . html ( ) + '</div>' ;
$ ( "#inputs" ) . append ( clone ) ;
$ ( "#inputs .txidClear:last" ) . remove ( ) ;
$ ( "#inputs .glyphicon-plus:last" ) . removeClass ( 'glyphicon-plus' ) . addClass ( 'glyphicon-minus' ) ;
$ ( "#inputs .glyphicon-minus:last" ) . parent ( ) . removeClass ( 'txidAdd' ) . addClass ( 'txidRemove' ) ;
$ ( "#inputs .txidRemove" ) . unbind ( "" ) ;
$ ( "#inputs .txidRemove" ) . click ( function ( ) {
$ ( this ) . parent ( ) . parent ( ) . fadeOut ( ) . remove ( ) ;
totalInputAmount ( ) ;
} ) ;
$ ( "#inputs .row:last input" ) . attr ( 'disabled' , false ) ;
$ ( "#inputs .txIdAmount" ) . unbind ( "" ) . change ( function ( ) {
totalInputAmount ( ) ;
} ) . keyup ( function ( ) {
totalInputAmount ( ) ;
} ) ;
} ) ;
$ ( "#transactionBtn" ) . click ( function ( ) {
var tx = coinjs . transaction ( ) ;
2016-05-26 14:32:52 +02:00
var estimatedTxSize = 10 ; // <4:version><1:txInCount><1:txOutCount><4:nLockTime>
2014-12-15 13:15:28 +01:00
2015-09-12 20:38:34 +02:00
$ ( "#transactionCreate, #transactionCreateStatus" ) . addClass ( "hidden" ) ;
2014-12-15 13:15:28 +01:00
if ( ( $ ( "#nLockTime" ) . val ( ) ) . match ( /^[0-9]+$/g ) ) {
tx . lock _time = $ ( "#nLockTime" ) . val ( ) * 1 ;
}
2015-09-12 20:38:34 +02:00
$ ( "#inputs .row" ) . removeClass ( 'has-error' ) ;
$ ( '#putTabs a[href="#txinputs"], #putTabs a[href="#txoutputs"]' ) . attr ( 'style' , '' ) ;
2014-12-02 00:36:49 +01:00
$ . each ( $ ( "#inputs .row" ) , function ( i , o ) {
2015-09-12 20:38:34 +02:00
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" ) ) {
2016-05-21 17:47:10 +02:00
var seq = null ;
if ( $ ( "#txRBF" ) . is ( ":checked" ) ) {
seq = 0xffffffff - 2 ;
}
2016-05-26 14:32:52 +02:00
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
}
2016-05-21 17:47:10 +02:00
tx . addinput ( $ ( ".txId" , o ) . val ( ) , $ ( ".txIdN" , o ) . val ( ) , $ ( ".txIdScript" , o ) . val ( ) , seq ) ;
2015-09-12 20:38:34 +02:00
} else {
$ ( '#putTabs a[href="#txinputs"]' ) . attr ( 'style' , 'color:#a94442;' ) ;
2014-12-02 00:36:49 +01:00
}
} ) ;
2014-12-29 23:55:28 +01:00
$ ( "#recipients .row" ) . removeClass ( 'has-error' ) ;
2014-12-02 00:36:49 +01:00
$ . each ( $ ( "#recipients .row" ) , function ( i , o ) {
2014-12-30 04:40:30 +01:00
var a = ( $ ( ".address" , o ) . val ( ) ) ;
2015-06-24 00:34:30 +02:00
var ad = coinjs . addressDecode ( a ) ;
2015-07-03 19:47:58 +02:00
if ( ( ( a != "" ) && ( ad . version == coinjs . pub || ad . version == coinjs . multisig ) ) && $ ( ".amount" , o ) . val ( ) != "" ) { // address
2016-05-26 14:32:52 +02:00
// P2SH output is 32, P2PKH is 34
estimatedTxSize += ( ad . version == coinjs . pub ? 34 : 32 )
2014-12-29 23:55:28 +01:00
tx . addoutput ( a , $ ( ".amount" , o ) . val ( ) ) ;
2015-01-02 14:52:01 +01:00
} else if ( ( ( a != "" ) && ad . version === 42 ) && $ ( ".amount" , o ) . val ( ) != "" ) { // stealth address
2016-05-26 14:32:52 +02:00
// 1 P2PKH and 1 OP_RETURN with 36 bytes, OP byte, and 8 byte value
estimatedTxSize += 78
2015-01-02 14:35:29 +01:00
tx . addstealth ( ad , $ ( ".amount" , o ) . val ( ) ) ;
2015-07-27 20:04:41 +02:00
} else if ( ( ( ( $ ( "#opReturn" ) . is ( ":checked" ) ) && a . match ( /^[a-f0-9]+$/ig ) ) && a . length < 160 ) && ( a . length % 2 ) == 0 ) { // data
2016-05-26 14:32:52 +02:00
estimatedTxSize += ( a . length / 2 ) + 1 + 8
2014-12-29 23:55:28 +01:00
tx . adddata ( a ) ;
} else { // neither address nor data
$ ( o ) . addClass ( 'has-error' ) ;
2015-09-12 20:38:34 +02:00
$ ( '#putTabs a[href="#txoutputs"]' ) . attr ( 'style' , 'color:#a94442;' ) ;
2014-12-02 00:36:49 +01:00
}
} ) ;
2015-09-12 20:38:34 +02:00
if ( ! $ ( "#recipients .row, #inputs .row" ) . hasClass ( 'has-error' ) ) {
$ ( "#transactionCreate textarea" ) . val ( tx . serialize ( ) ) ;
$ ( "#transactionCreate .txSize" ) . html ( tx . size ( ) ) ;
$ ( "#transactionCreate" ) . removeClass ( "hidden" ) ;
2016-05-26 14:32:52 +02:00
// 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 ) {
2015-09-12 20:38:34 +02:00
$ ( "#modalWarningFeeAmount" ) . html ( $ ( "#transactionFee" ) . val ( ) ) ;
$ ( "#modalWarningFee" ) . modal ( "show" ) ;
}
} else {
$ ( "#transactionCreateStatus" ) . removeClass ( "hidden" ) . html ( "One or more input or output is invalid" ) . fadeOut ( ) . fadeIn ( ) ;
}
2014-12-02 00:36:49 +01:00
} ) ;
$ ( ".txidClear" ) . click ( function ( ) {
$ ( "#inputs .row:first input" ) . attr ( 'disabled' , false ) ;
$ ( "#inputs .row:first input" ) . val ( "" ) ;
totalInputAmount ( ) ;
} ) ;
$ ( "#inputs .txIdAmount" ) . unbind ( "" ) . change ( function ( ) {
totalInputAmount ( ) ;
} ) . keyup ( function ( ) {
totalInputAmount ( ) ;
} ) ;
2015-03-09 01:34:19 +01:00
/* code for the qr code scanner */
2015-03-09 13:27:28 +01:00
$ ( ".qrcodeScanner" ) . click ( function ( ) {
if ( ( typeof MediaStreamTrack === 'function' ) && typeof MediaStreamTrack . getSources === 'function' ) {
MediaStreamTrack . getSources ( function ( sourceInfos ) {
var f = 0 ;
$ ( "select#videoSource" ) . html ( "" ) ;
for ( var i = 0 ; i !== sourceInfos . length ; ++ i ) {
var sourceInfo = sourceInfos [ i ] ;
var option = document . createElement ( 'option' ) ;
option . value = sourceInfo . id ;
if ( sourceInfo . kind === 'video' ) {
option . text = sourceInfo . label || 'camera ' + ( $ ( "select#videoSource options" ) . length + 1 ) ;
$ ( option ) . appendTo ( "select#videoSource" ) ;
}
2015-03-09 01:34:19 +01:00
}
2015-03-09 13:27:28 +01:00
} ) ;
2015-03-09 13:31:52 +01:00
$ ( "#videoSource" ) . unbind ( "change" ) . change ( function ( ) {
scannerStart ( )
} ) ;
2015-03-09 13:27:28 +01:00
} else {
$ ( "#videoSource" ) . addClass ( "hidden" ) ;
}
2015-03-09 13:31:52 +01:00
scannerStart ( ) ;
2015-03-09 01:34:19 +01:00
$ ( "#qrcode-scanner-callback-to" ) . html ( $ ( this ) . attr ( 'forward-result' ) ) ;
} ) ;
2015-03-09 13:31:52 +01:00
function scannerStart ( ) {
2015-03-09 13:27:28 +01:00
navigator . getUserMedia = navigator . getUserMedia || navigator . webkitGetUserMedia || navigator . mozGetUserMedia || false ;
if ( navigator . getUserMedia ) {
if ( ! ! window . stream ) {
$ ( "video" ) . attr ( 'src' , null ) ;
window . stream . stop ( ) ;
}
var videoSource = $ ( "select#videoSource" ) . val ( ) ;
var constraints = {
video : {
optional : [ { sourceId : videoSource } ]
}
} ;
navigator . getUserMedia ( constraints , function ( stream ) {
window . stream = stream ; // make stream available to console
var videoElement = document . querySelector ( 'video' ) ;
videoElement . src = window . URL . createObjectURL ( stream ) ;
videoElement . play ( ) ;
} , function ( error ) { } ) ;
QCodeDecoder ( ) . decodeFromCamera ( document . getElementById ( 'videoReader' ) , function ( er , data ) {
if ( ! er ) {
var match = data . match ( /^bitcoin\:([13][a-z0-9]{26,33})/i ) ;
var result = match ? match [ 1 ] : data ;
$ ( "" + $ ( "#qrcode-scanner-callback-to" ) . html ( ) ) . val ( result ) ;
$ ( "#qrScanClose" ) . click ( ) ;
}
} ) ;
} else {
$ ( "#videoReaderError" ) . removeClass ( "hidden" ) ;
$ ( "#videoReader, #videoSource" ) . addClass ( "hidden" ) ;
}
}
2015-08-14 23:07:19 +02:00
/* redeem from button code */
2014-12-02 00:36:49 +01:00
$ ( "#redeemFromBtn" ) . click ( function ( ) {
2015-08-15 00:09:51 +02:00
var redeem = redeemingFrom ( $ ( "#redeemFrom" ) . val ( ) ) ;
2014-12-02 00:36:49 +01:00
$ ( "#redeemFromStatus, #redeemFromAddress" ) . addClass ( 'hidden' ) ;
2015-08-14 23:07:19 +02:00
if ( redeem . from == 'multisigAddress' ) {
2014-12-02 00:36:49 +01:00
$ ( "#redeemFromStatus" ) . removeClass ( 'hidden' ) . html ( '<span class="glyphicon glyphicon-exclamation-sign"></span> You should use the redeem script, not the multisig address!' ) ;
2015-08-14 23:07:19 +02:00
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 ;
}
if ( $ ( "#clearInputsOnLoad" ) . is ( ":checked" ) ) {
$ ( "#inputs .txidRemove, #inputs .txidClear" ) . click ( ) ;
}
$ ( "#redeemFromBtn" ) . html ( "Please wait, loading..." ) . attr ( 'disabled' , true ) ;
var host = $ ( this ) . attr ( 'rel' ) ;
if ( host == 'blockr.io_bitcoinmainnet' ) {
2015-08-15 00:09:51 +02:00
listUnspentBlockrio _BitcoinMainnet ( redeem ) ;
2015-08-14 23:07:19 +02:00
} else if ( host == 'chain.so_litecoin' ) {
2015-08-15 00:09:51 +02:00
listUnspentChainso _Litecoin ( redeem ) ;
2015-08-14 23:07:19 +02:00
} else {
2015-08-15 00:09:51 +02:00
listUnspentDefault ( redeem ) ;
2015-08-14 23:07:19 +02:00
}
2015-12-27 05:15:47 +01:00
if ( $ ( "#redeemFromStatus" ) . hasClass ( "hidden" ) ) {
// An ethical dilemma: Should we automatically set nLockTime?
if ( redeem . from == 'redeemScript' && redeem . decodedRs . type == "hodl__" ) {
2015-12-29 04:00:11 +01:00
$ ( "#nLockTime" ) . val ( redeem . decodedRs . checklocktimeverify ) ;
2015-12-27 05:15:47 +01:00
} else {
$ ( "#nLockTime" ) . val ( 0 ) ;
}
}
2015-08-14 23:07:19 +02:00
} ) ;
/* 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 ;
2014-12-02 00:36:49 +01:00
} else {
var script = coinjs . script ( ) ;
2015-08-14 23:07:19 +02:00
var decodeRs = script . decodeRedeemScript ( string ) ;
if ( decodeRs ) { // redeem script
r . addr = decodeRs [ 'address' ] ;
r . from = 'redeemScript' ;
2015-09-12 20:38:34 +02:00
r . decodedRs = decodeRs ;
2015-12-27 05:15:47 +01:00
r . isMultisig = true ; // not quite, may be hodl
2015-08-14 23:07:19 +02:00
} else { // something else
r . addr = '' ;
r . from = 'other' ;
r . isMultisig = false ;
2014-12-02 00:36:49 +01:00
}
}
2015-08-14 23:07:19 +02:00
return r ;
}
2014-12-02 00:36:49 +01:00
2015-09-12 20:38:34 +02:00
/* 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 ( ) ;
}
}
2015-08-14 23:07:19 +02:00
/* 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 txid = ( ( tx ) . match ( /.{1,2}/g ) . reverse ( ) ) . join ( "" ) + '' ;
$ ( "#inputs .txId:last" ) . val ( txid ) ;
$ ( "#inputs .txIdN:last" ) . val ( n ) ;
$ ( "#inputs .txIdAmount:last" ) . val ( amount ) ;
$ ( "#inputs .txIdScript:last" ) . val ( script ) ;
}
}
/* default function to retreive unspent outputs*/
2015-08-15 00:09:51 +02:00
function listUnspentDefault ( redeem ) {
2014-12-02 00:36:49 +01:00
var tx = coinjs . transaction ( ) ;
2015-08-15 00:09:51 +02:00
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="https://btc.blockr.io/address/info/' + redeem . addr + '" target="_blank">' + redeem . addr + '</a>' ) ;
2014-12-02 00:36:49 +01:00
$ . each ( $ ( data ) . find ( "unspent" ) . children ( ) , function ( i , o ) {
2015-08-14 23:07:19 +02:00
var tx = $ ( o ) . find ( "tx_hash" ) . text ( ) ;
var n = $ ( o ) . find ( "tx_output_n" ) . text ( ) ;
2015-08-15 00:09:51 +02:00
var script = ( redeem . isMultisig == true ) ? $ ( "#redeemFrom" ) . val ( ) : $ ( o ) . find ( "script" ) . text ( ) ;
2015-08-14 23:07:19 +02:00
var amount = ( ( $ ( o ) . find ( "value" ) . text ( ) * 1 ) / 100000000 ) . toFixed ( 8 ) ;
2014-12-15 01:24:31 +01:00
2015-08-14 23:07:19 +02:00
addOutput ( tx , n , script , amount ) ;
} ) ;
}
2014-12-15 01:24:31 +01:00
2015-08-14 23:07:19 +02:00
$ ( "#redeemFromBtn" ) . html ( "Load" ) . attr ( 'disabled' , false ) ;
totalInputAmount ( ) ;
2015-09-12 20:38:34 +02:00
mediatorPayment ( redeem ) ;
2015-08-14 23:07:19 +02:00
} ) ;
}
2014-12-02 00:36:49 +01:00
2015-08-14 23:07:19 +02:00
/* retrieve unspent data from blockrio for mainnet */
2015-08-15 00:09:51 +02:00
function listUnspentBlockrio _BitcoinMainnet ( redeem ) {
2015-08-14 23:07:19 +02:00
$ . ajax ( {
type : "POST" ,
2015-08-30 03:51:42 +02:00
url : "https://btc.blockr.io/api/v1/address/unspent/" + redeem . addr + "?unconfirmed=1" ,
2015-08-14 23:07:19 +02:00
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' ) {
2015-08-15 00:09:51 +02:00
$ ( "#redeemFromAddress" ) . removeClass ( 'hidden' ) . html ( '<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="https://btc.blockr.io/address/info/' + redeem . addr + '" target="_blank">' + redeem . addr + '</a>' ) ;
2015-08-14 23:07:19 +02:00
for ( var i in data . data . unspent ) {
var o = data . data . unspent [ i ] ;
var tx = o . tx ;
var n = o . n ;
2015-08-15 00:09:51 +02:00
var script = ( redeem . isMultisig == true ) ? $ ( "#redeemFrom" ) . val ( ) : o . script ;
2015-08-14 23:07:19 +02:00
var amount = o . amount ;
addOutput ( tx , n , script , amount ) ;
2014-12-02 00:36:49 +01:00
}
2015-08-14 23:07:19 +02:00
} 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 ( ) ;
2014-12-02 00:36:49 +01:00
}
2015-08-14 23:07:19 +02:00
} ) ;
}
2014-12-02 00:36:49 +01:00
2015-08-14 23:07:19 +02:00
/* retrieve unspent data from blockrio for litecoin */
2015-08-15 00:09:51 +02:00
function listUnspentChainso _Litecoin ( redeem ) {
2015-08-14 23:07:19 +02:00
$ . ajax ( {
type : "GET" ,
2015-08-15 00:09:51 +02:00
url : "https://chain.so/api/v2/get_tx_unspent/ltc/" + redeem . addr ,
2015-08-14 23:07:19 +02:00
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' ) {
2015-08-15 00:09:51 +02:00
$ ( "#redeemFromAddress" ) . removeClass ( 'hidden' ) . html ( '<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="https://btc.blockr.io/address/info/' + redeem . addr + '" target="_blank">' + redeem . addr + '</a>' ) ;
2015-08-14 23:07:19 +02:00
for ( var i in data . data . txs ) {
var o = data . data . txs [ i ] ;
2015-09-12 20:38:34 +02:00
var tx = ( ( o . txid ) . match ( /.{1,2}/g ) . reverse ( ) ) . join ( "" ) + '' ;
2015-08-14 23:07:19 +02:00
var n = o . output _no ;
2015-08-15 00:09:51 +02:00
var script = ( redeem . isMultisig == true ) ? $ ( "#redeemFrom" ) . val ( ) : o . script _hex ;
2015-08-14 23:07:19 +02:00
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 ( ) ;
}
2014-12-02 00:36:49 +01:00
} ) ;
2015-08-14 23:07:19 +02:00
}
/* math to calculate the inputs and outputs */
2014-12-02 00:36:49 +01:00
function totalInputAmount ( ) {
$ ( "#totalInput" ) . html ( '0.00' ) ;
$ . each ( $ ( "#inputs .txIdAmount" ) , function ( i , o ) {
if ( isNaN ( $ ( o ) . val ( ) ) ) {
$ ( o ) . parent ( ) . addClass ( 'has-error' ) ;
} else {
$ ( o ) . parent ( ) . removeClass ( 'has-error' ) ;
var f = 0 ;
if ( ! isNaN ( $ ( o ) . val ( ) ) ) {
f += $ ( o ) . val ( ) * 1 ;
}
$ ( "#totalInput" ) . html ( ( ( $ ( "#totalInput" ) . html ( ) * 1 ) + ( f * 1 ) ) . toFixed ( 8 ) ) ;
}
} ) ;
totalFee ( ) ;
}
function validateOutputAmount ( ) {
$ ( "#recipients .amount" ) . unbind ( '' ) ;
$ ( "#recipients .amount" ) . keyup ( function ( ) {
if ( isNaN ( $ ( this ) . val ( ) ) ) {
$ ( this ) . parent ( ) . addClass ( 'has-error' ) ;
} else {
$ ( this ) . parent ( ) . removeClass ( 'has-error' ) ;
var f = 0 ;
$ . each ( $ ( "#recipients .amount" ) , function ( i , o ) {
if ( ! isNaN ( $ ( o ) . val ( ) ) ) {
f += $ ( o ) . val ( ) * 1 ;
}
} ) ;
$ ( "#totalOutput" ) . html ( ( f ) . toFixed ( 8 ) ) ;
}
totalFee ( ) ;
} ) . keyup ( ) ;
}
function totalFee ( ) {
var fee = ( ( $ ( "#totalInput" ) . html ( ) * 1 ) - ( $ ( "#totalOutput" ) . html ( ) * 1 ) ) . toFixed ( 8 ) ;
$ ( "#transactionFee" ) . val ( ( fee > 0 ) ? fee : '0.00' ) ;
}
2014-12-15 13:15:28 +01:00
$ ( "#optionsCollapse" ) . click ( function ( ) {
if ( $ ( "#optionsAdvanced" ) . hasClass ( 'hidden' ) ) {
$ ( "#glyphcollapse" ) . removeClass ( 'glyphicon-collapse-down' ) . addClass ( 'glyphicon-collapse-up' ) ;
$ ( "#optionsAdvanced" ) . removeClass ( "hidden" ) ;
} else {
$ ( "#glyphcollapse" ) . removeClass ( 'glyphicon-collapse-up' ) . addClass ( 'glyphicon-collapse-down' ) ;
$ ( "#optionsAdvanced" ) . addClass ( "hidden" ) ;
}
} ) ;
2014-12-02 00:36:49 +01:00
/* broadcast a transaction */
$ ( "#rawSubmitBtn" ) . click ( function ( ) {
2015-06-24 00:34:30 +02:00
rawSubmitDefault ( this ) ;
} ) ;
// broadcast transaction vai coinbin (default)
function rawSubmitDefault ( btn ) {
2015-09-16 13:41:18 +02:00
var thisbtn = btn ;
2014-12-05 14:04:00 +01:00
$ ( thisbtn ) . val ( 'Please wait, loading...' ) . attr ( 'disabled' , true ) ;
2015-09-16 13:41:18 +02:00
$ . 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' ) ;
$ ( "#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 ) ;
2014-12-02 00:36:49 +01:00
}
2015-09-16 13:41:18 +02:00
} ) ;
2015-06-24 00:34:30 +02:00
}
// broadcast transaction via blockr.io (mainnet)
function rawSubmitBlockrio _BitcoinMainnet ( 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 ( ) } ,
dataType : "json" ,
error : function ( data ) {
var obj = $ . parseJSON ( data . responseText ) ;
var r = ' ' ;
r += ( obj . data ) ? obj . data : '' ;
r += ( obj . message ) ? ' ' + obj . message : '' ;
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 ) {
2016-07-29 01:40:31 +02:00
if ( ( data . status && data . data ) && data . status == 'success' ) {
$ ( "#rawTransactionStatus" ) . addClass ( 'alert-success' ) . removeClass ( 'alert-danger' ) . removeClass ( "hidden" ) . html ( ' Txid: ' + data . data ) ;
2015-06-24 00:34:30 +02:00
} 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 ) ;
}
} ) ;
}
2016-03-16 00:47:40 +01:00
// broadcast transaction via blockr.io (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 . 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 ) {
2016-07-29 01:40:31 +02:00
if ( data . status && data . data . txid ) {
$ ( "#rawTransactionStatus" ) . addClass ( 'alert-success' ) . removeClass ( 'alert-danger' ) . removeClass ( "hidden" ) . html ( ' Txid: ' + data . data . txid ) ;
2016-03-16 00:47:40 +01:00
} 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 ) ;
}
} ) ;
}
2016-03-21 14:34:19 +01:00
// broadcast transaction via blockcypher.com (mainnet)
function rawSubmitblockcypher _BitcoinMainnet ( thisbtn ) {
$ ( thisbtn ) . val ( 'Please wait, loading...' ) . attr ( 'disabled' , true ) ;
$ . ajax ( {
type : "POST" ,
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 . 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 ) {
2016-07-29 01:40:31 +02:00
if ( ( data . tx ) && data . tx . hash ) {
$ ( "#rawTransactionStatus" ) . addClass ( 'alert-success' ) . removeClass ( 'alert-danger' ) . removeClass ( "hidden" ) . html ( ' Txid: ' + data . tx . hash ) ;
2016-03-21 14:34:19 +01:00
} else {
$ ( "#rawTransactionStatus" ) . addClass ( 'alert-danger' ) . removeClass ( 'alert-success' ) . removeClass ( "hidden" ) . html ( ' Unexpected error, please try again' ) . prepend ( '<span class="glyphicon glyphicon-exclamation-sign"></span>' ) ;
2016-07-29 01:40:31 +02:00
}
2016-03-21 14:34:19 +01:00
} ,
complete : function ( data , status ) {
$ ( "#rawTransactionStatus" ) . fadeOut ( ) . fadeIn ( ) ;
$ ( thisbtn ) . val ( 'Submit' ) . attr ( 'disabled' , false ) ;
}
} ) ;
}
2015-08-14 23:07:19 +02:00
// broadcast transaction via blockr.io for litecoin
function rawSubmitBlockrio _litecoin ( thisbtn ) {
2015-06-24 00:34:30 +02:00
$ ( thisbtn ) . val ( 'Please wait, loading...' ) . attr ( 'disabled' , true ) ;
$ . ajax ( {
type : "POST" ,
2015-08-14 23:07:19 +02:00
url : "https://ltc.blockr.io/api/v1/tx/push" ,
2015-06-24 00:34:30 +02:00
data : { "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 = ( 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 ) {
2016-07-29 01:40:31 +02:00
if ( ( data . status && data . data ) && data . status == 'success' ) {
$ ( "#rawTransactionStatus" ) . addClass ( 'alert-success' ) . removeClass ( 'alert-danger' ) . removeClass ( "hidden" ) . html ( ' Txid: ' + data . data ) ;
2015-06-24 00:34:30 +02:00
} 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 ) ;
}
} ) ;
}
2014-12-02 00:36:49 +01:00
/* verify script code */
$ ( "#verifyBtn" ) . click ( function ( ) {
$ ( ".verifyData" ) . addClass ( "hidden" ) ;
$ ( "#verifyStatus" ) . hide ( ) ;
if ( ! decodeRedeemScript ( ) ) {
if ( ! decodeTransactionScript ( ) ) {
if ( ! decodePrivKey ( ) ) {
if ( ! decodePubKey ( ) ) {
2015-05-17 02:30:21 +02:00
if ( ! decodeHDaddress ( ) ) {
$ ( "#verifyStatus" ) . removeClass ( 'hidden' ) . fadeOut ( ) . fadeIn ( ) ;
}
2014-12-02 00:36:49 +01:00
}
}
}
}
} ) ;
function decodeRedeemScript ( ) {
var script = coinjs . script ( ) ;
var decode = script . decodeRedeemScript ( $ ( "#verifyScript" ) . val ( ) ) ;
if ( decode ) {
2015-12-27 04:37:51 +01:00
$ ( "#verifyRsDataMultisig" ) . addClass ( 'hidden' ) ;
$ ( "#verifyRsDataHodl" ) . 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 ++ ) {
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 == "hodl__" ) {
var d = $ ( "#verifyRsDataHodl .date" ) . data ( "DateTimePicker" ) ;
$ ( "#verifyRsDataHodl .address" ) . val ( decode [ 'address' ] ) ;
$ ( "#verifyRsDataHodl .pubkey" ) . val ( coinjs . pubkey2address ( decode [ 'pubkey' ] ) ) ;
2015-12-29 04:00:11 +01:00
$ ( "#verifyRsDataHodl .date" ) . val ( decode [ 'checklocktimeverify' ] >= 500000000 ? moment . unix ( decode [ 'checklocktimeverify' ] ) . format ( "MM/DD/YYYY HH:mm" ) : decode [ 'checklocktimeverify' ] ) ;
2015-12-27 04:37:51 +01:00
$ ( "#verifyRsData" ) . removeClass ( "hidden" ) ;
$ ( "#verifyRsDataHodl" ) . removeClass ( 'hidden' ) ;
$ ( ".verifyLink" ) . attr ( 'href' , '?verify=' + $ ( "#verifyScript" ) . val ( ) ) ;
return true ;
2014-12-02 00:36:49 +01:00
}
}
2015-12-27 04:37:51 +01:00
return false ;
2014-12-02 00:36:49 +01:00
}
function decodeTransactionScript ( ) {
var tx = coinjs . transaction ( ) ;
try {
var decode = tx . deserialize ( $ ( "#verifyScript" ) . val ( ) ) ;
2014-12-15 13:15:28 +01:00
// console.log(decode);
2014-12-02 00:36:49 +01:00
$ ( "#verifyTransactionData .transactionVersion" ) . html ( decode [ 'version' ] ) ;
$ ( "#verifyTransactionData .transactionSize" ) . html ( decode . size ( ) + ' <i>bytes</i>' ) ;
$ ( "#verifyTransactionData .transactionLockTime" ) . html ( decode [ 'lock_time' ] ) ;
2016-05-21 17:47:10 +02:00
$ ( "#verifyTransactionData .transactionRBF" ) . hide ( ) ;
2014-12-02 00:36:49 +01:00
$ ( "#verifyTransactionData" ) . removeClass ( "hidden" ) ;
$ ( "#verifyTransactionData tbody" ) . html ( "" ) ;
var h = '' ;
$ . each ( decode . ins , function ( i , o ) {
var s = decode . extractScriptKey ( i ) ;
h += '<tr>' ;
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>' ;
if ( s [ 'type' ] == 'multisig' && s [ 'signatures' ] >= 1 ) {
h += ' ' + s [ 'signatures' ] ;
}
h += '</td>' ;
h += '<td class="col-xs-1">' ;
if ( s [ 'type' ] == 'multisig' ) {
var script = coinjs . script ( ) ;
var rs = script . decodeRedeemScript ( s . script ) ;
h += rs [ 'signaturesRequired' ] + ' of ' + rs [ 'pubkeys' ] . length ;
} else {
h += '<span class="glyphicon glyphicon-remove-circle"></span>' ;
}
h += '</td>' ;
h += '</tr>' ;
2016-05-21 17:47:10 +02:00
//debug
if ( parseInt ( o . sequence ) < ( 0xFFFFFFFF - 1 ) ) {
$ ( "#verifyTransactionData .transactionRBF" ) . show ( ) ;
}
2014-12-02 00:36:49 +01:00
} ) ;
2014-12-29 23:55:28 +01:00
2014-12-02 00:36:49 +01:00
$ ( h ) . appendTo ( "#verifyTransactionData .ins tbody" ) ;
h = '' ;
$ . each ( decode . outs , function ( i , o ) {
2014-12-29 23:55:28 +01:00
if ( o . script . chunks . length == 2 && o . script . chunks [ 0 ] == 106 ) { // OP_RETURN
var data = Crypto . util . bytesToHex ( o . script . chunks [ 1 ] ) ;
var dataascii = hex2ascii ( data ) ;
if ( dataascii . match ( /^[\s\d\w]+$/ig ) ) {
data = dataascii ;
}
h += '<tr>' ;
h += '<td><input type="text" class="form-control" value="(OP_RETURN) ' + data + '" readonly></td>' ;
h += '<td class="col-xs-1">' + ( o . value / 100000000 ) . toFixed ( 8 ) + '</td>' ;
h += '<td class="col-xs-2"><input class="form-control" type="text" value="' + Crypto . util . bytesToHex ( o . script . buffer ) + '" readonly></td>' ;
h += '</tr>' ;
2014-12-02 00:36:49 +01:00
} else {
2014-12-29 23:55:28 +01:00
var addr = '' ;
if ( o . script . chunks . length == 5 ) {
addr = coinjs . scripthash2address ( Crypto . util . bytesToHex ( o . script . chunks [ 2 ] ) ) ;
} else {
var pub = coinjs . pub ;
coinjs . pub = coinjs . multisig ;
addr = coinjs . scripthash2address ( Crypto . util . bytesToHex ( o . script . chunks [ 1 ] ) ) ;
coinjs . pub = pub ;
}
h += '<tr>' ;
h += '<td><input class="form-control" type="text" value="' + addr + '" readonly></td>' ;
h += '<td class="col-xs-1">' + ( o . value / 100000000 ) . toFixed ( 8 ) + '</td>' ;
h += '<td class="col-xs-2"><input class="form-control" type="text" value="' + Crypto . util . bytesToHex ( o . script . buffer ) + '" readonly></td>' ;
h += '</tr>' ;
}
2014-12-02 00:36:49 +01:00
} ) ;
$ ( h ) . appendTo ( "#verifyTransactionData .outs tbody" ) ;
2015-03-23 14:02:29 +01:00
$ ( ".verifyLink" ) . attr ( 'href' , '?verify=' + $ ( "#verifyScript" ) . val ( ) ) ;
2014-12-02 00:36:49 +01:00
return true ;
} catch ( e ) {
return false ;
}
}
2014-12-29 23:55:28 +01:00
function hex2ascii ( hex ) {
var str = '' ;
for ( var i = 0 ; i < hex . length ; i += 2 )
str += String . fromCharCode ( parseInt ( hex . substr ( i , 2 ) , 16 ) ) ;
return str ;
}
2014-12-02 00:36:49 +01:00
function decodePrivKey ( ) {
var wif = $ ( "#verifyScript" ) . val ( ) ;
if ( wif . length == 51 || wif . length == 52 ) {
try {
var w2address = coinjs . wif2address ( wif ) ;
var w2pubkey = coinjs . wif2pubkey ( wif ) ;
var w2privkey = coinjs . wif2privkey ( wif ) ;
$ ( "#verifyPrivKey .address" ) . val ( w2address [ 'address' ] ) ;
$ ( "#verifyPrivKey .pubkey" ) . val ( w2pubkey [ 'pubkey' ] ) ;
$ ( "#verifyPrivKey .privkey" ) . val ( w2privkey [ 'privkey' ] ) ;
$ ( "#verifyPrivKey .iscompressed" ) . html ( w2address [ 'compressed' ] ? 'true' : 'false' ) ;
$ ( "#verifyPrivKey" ) . removeClass ( "hidden" ) ;
return true ;
} catch ( e ) {
return false ;
}
} else {
return false ;
}
}
function decodePubKey ( ) {
var pubkey = $ ( "#verifyScript" ) . val ( ) ;
if ( pubkey . length == 66 || pubkey . length == 130 ) {
try {
$ ( "#verifyPubKey .address" ) . val ( coinjs . pubkey2address ( pubkey ) ) ;
$ ( "#verifyPubKey" ) . removeClass ( "hidden" ) ;
2015-03-23 14:02:29 +01:00
$ ( ".verifyLink" ) . attr ( 'href' , '?verify=' + $ ( "#verifyScript" ) . val ( ) ) ;
2014-12-02 00:36:49 +01:00
return true ;
} catch ( e ) {
return false ;
}
} else {
return false ;
}
}
2015-05-17 02:30:21 +02:00
function decodeHDaddress ( ) {
var s = $ ( "#verifyScript" ) . val ( ) ;
2015-05-20 15:05:19 +02:00
try {
var hex = Crypto . util . bytesToHex ( ( coinjs . base58decode ( s ) ) . slice ( 0 , 4 ) ) ;
var hex _cmp _prv = Crypto . util . bytesToHex ( ( coinjs . numToBytes ( coinjs . hdkey . prv , 4 ) ) . reverse ( ) ) ;
var hex _cmp _pub = Crypto . util . bytesToHex ( ( coinjs . numToBytes ( coinjs . hdkey . pub , 4 ) ) . reverse ( ) ) ;
if ( hex == hex _cmp _prv || hex == hex _cmp _pub ) {
2015-05-17 02:30:21 +02:00
var hd = coinjs . hd ( s ) ;
$ ( "#verifyHDaddress .hdKey" ) . html ( s ) ;
$ ( "#verifyHDaddress .chain_code" ) . val ( Crypto . util . bytesToHex ( hd . chain _code ) ) ;
$ ( "#verifyHDaddress .depth" ) . val ( hd . depth ) ;
$ ( "#verifyHDaddress .version" ) . val ( '0x' + ( hd . version ) . toString ( 16 ) ) ;
$ ( "#verifyHDaddress .child_index" ) . val ( hd . child _index ) ;
$ ( "#verifyHDaddress .hdwifkey" ) . val ( ( hd . keys . wif ) ? hd . keys . wif : '' ) ;
$ ( "#verifyHDaddress .key_type" ) . html ( ( ( ( hd . depth == 0 && hd . child _index == 0 ) ? 'Master' : 'Derived' ) + ' ' + hd . type ) . toLowerCase ( ) ) ;
$ ( "#verifyHDaddress .parent_fingerprint" ) . val ( Crypto . util . bytesToHex ( hd . parent _fingerprint ) ) ;
$ ( "#verifyHDaddress .derived_data table tbody" ) . html ( "" ) ;
deriveHDaddress ( ) ;
$ ( ".verifyLink" ) . attr ( 'href' , '?verify=' + $ ( "#verifyScript" ) . val ( ) ) ;
$ ( "#verifyHDaddress" ) . removeClass ( "hidden" ) ;
return true ;
}
2015-05-20 15:05:19 +02:00
} catch ( e ) {
return false ;
2015-05-17 02:30:21 +02:00
}
}
function deriveHDaddress ( ) {
var hd = coinjs . hd ( $ ( "#verifyHDaddress .hdKey" ) . html ( ) ) ;
var index _start = $ ( "#verifyHDaddress .derivation_index_start" ) . val ( ) * 1 ;
var index _end = $ ( "#verifyHDaddress .derivation_index_end" ) . val ( ) * 1 ;
var html = '' ;
$ ( "#verifyHDaddress .derived_data table tbody" ) . html ( "" ) ;
for ( var i = index _start ; i <= index _end ; i ++ ) {
var derived = hd . derive ( i ) ;
html += '<tr>' ;
html += '<td>' + i + '</td>' ;
html += '<td><input type="text" class="form-control" value="' + derived . keys . address + '" readonly></td>' ;
html += '<td><input type="text" class="form-control" value="' + ( ( derived . keys . wif ) ? derived . keys . wif : '' ) + '" readonly></td>' ;
html += '<td><input type="text" class="form-control" value="' + derived . keys _extended . pubkey + '" readonly></td>' ;
html += '<td><input type="text" class="form-control" value="' + ( ( derived . keys _extended . privkey ) ? derived . keys _extended . privkey : '' ) + '" readonly></td>' ;
html += '</tr>' ;
}
$ ( html ) . appendTo ( "#verifyHDaddress .derived_data table tbody" ) ;
}
2014-12-02 00:36:49 +01:00
/* sign code */
$ ( "#signBtn" ) . click ( function ( ) {
var wifkey = $ ( "#signPrivateKey" ) ;
var script = $ ( "#signTransaction" ) ;
if ( coinjs . addressDecode ( wifkey . val ( ) ) ) {
$ ( wifkey ) . parent ( ) . removeClass ( 'has-error' ) ;
} else {
$ ( wifkey ) . parent ( ) . addClass ( 'has-error' ) ;
}
if ( ( script . val ( ) ) . match ( /^[a-f0-9]+$/ig ) ) {
$ ( script ) . parent ( ) . removeClass ( 'has-error' ) ;
} else {
$ ( script ) . parent ( ) . addClass ( 'has-error' ) ;
}
if ( $ ( "#sign .has-error" ) . length == 0 ) {
$ ( "#signedDataError" ) . addClass ( 'hidden' ) ;
try {
var tx = coinjs . transaction ( ) ;
var t = tx . deserialize ( script . val ( ) ) ;
2014-12-15 14:54:13 +01:00
2014-12-02 00:36:49 +01:00
var signed = t . sign ( wifkey . val ( ) ) ;
$ ( "#signedData textarea" ) . val ( signed ) ;
$ ( "#signedData .txSize" ) . html ( t . size ( ) ) ;
$ ( "#signedData" ) . removeClass ( 'hidden' ) . fadeIn ( ) ;
} catch ( e ) {
// console.log(e);
}
} else {
$ ( "#signedDataError" ) . removeClass ( 'hidden' ) ;
$ ( "#signedData" ) . addClass ( 'hidden' ) ;
}
} ) ;
/* page load code */
2014-12-23 15:25:43 +01:00
function _get ( value ) {
var dataArray = ( document . location . search ) . match ( /(([a-z0-9\_\[\]]+\=[a-z0-9\_\.\%\@]+))/gi ) ;
var r = [ ] ;
if ( dataArray ) {
for ( var x in dataArray ) {
if ( ( dataArray [ x ] ) && typeof ( dataArray [ x ] ) == 'string' ) {
if ( ( dataArray [ x ] . split ( '=' ) [ 0 ] . toLowerCase ( ) ) . replace ( /\[\]$/ig , '' ) == value . toLowerCase ( ) ) {
r . push ( unescape ( dataArray [ x ] . split ( '=' ) [ 1 ] ) ) ;
}
}
}
}
return r ;
}
2015-05-20 15:05:19 +02:00
$ ( "#newKeysBtn, #newHDKeysBtn" ) . click ( ) ;
2014-12-23 15:25:43 +01:00
var _getBroadcast = _get ( "broadcast" ) ;
if ( _getBroadcast [ 0 ] ) {
$ ( "#rawTransaction" ) . val ( _getBroadcast [ 0 ] ) ;
$ ( "#rawSubmitBtn" ) . click ( ) ;
2014-12-24 19:35:42 +01:00
window . location . hash = "#broadcast" ;
2014-12-23 15:25:43 +01:00
}
var _getVerify = _get ( "verify" ) ;
if ( _getVerify [ 0 ] ) {
$ ( "#verifyScript" ) . val ( _getVerify [ 0 ] ) ;
$ ( "#verifyBtn" ) . click ( ) ;
2014-12-24 19:35:42 +01:00
window . location . hash = "#verify" ;
2014-12-23 15:25:43 +01:00
}
2014-12-02 00:36:49 +01:00
$ ( ".qrcodeBtn" ) . click ( function ( ) {
2014-12-07 20:12:52 +01:00
$ ( "#qrcode" ) . html ( "" ) ;
2014-12-02 00:36:49 +01:00
var thisbtn = $ ( this ) . parent ( ) . parent ( ) ;
2015-06-22 12:41:21 +02:00
var qrstr = false ;
var ta = $ ( "textarea" , thisbtn ) ;
if ( ta . length > 0 ) {
var w = ( screen . availWidth > screen . availHeight ? screen . availWidth : screen . availHeight ) / 3 ;
var qrcode = new QRCode ( "qrcode" , { width : w , height : w } ) ;
qrstr = $ ( ta ) . val ( ) ;
2015-06-22 12:47:54 +02:00
if ( qrstr . length > 1024 ) {
2015-06-22 10:55:30 +02:00
$ ( "#qrcode" ) . html ( "<p>Sorry the data is too long for the QR generator.</p>" ) ;
}
2015-06-22 12:41:21 +02:00
} else {
2015-06-22 10:55:30 +02:00
var qrcode = new QRCode ( "qrcode" ) ;
2015-06-22 12:41:21 +02:00
qrstr = "bitcoin:" + $ ( '.address' , thisbtn ) . val ( ) ;
}
if ( qrstr ) {
qrcode . makeCode ( qrstr ) ;
2015-06-22 10:55:30 +02:00
}
2014-12-02 00:36:49 +01:00
} ) ;
$ ( 'input[title!=""], abbr[title!=""]' ) . tooltip ( { 'placement' : 'bottom' } ) ;
if ( location . hash !== '' ) {
$ ( 'a[href="' + location . hash + '"]' ) . tab ( 'show' ) ;
}
$ ( ".showKey" ) . click ( function ( ) {
$ ( "input[type='password']" , $ ( this ) . parent ( ) . parent ( ) ) . attr ( 'type' , 'text' ) ;
} ) ;
$ ( "#homeBtn" ) . click ( function ( e ) {
e . preventDefault ( ) ;
history . pushState ( null , null , '#home' ) ;
$ ( "#header .active, #content .tab-content" ) . removeClass ( "active" ) ;
$ ( "#home" ) . addClass ( "active" ) ;
} ) ;
$ ( 'a[data-toggle="tab"]' ) . on ( 'click' , function ( e ) {
e . preventDefault ( ) ;
if ( e . target ) {
history . pushState ( null , null , '#' + $ ( e . target ) . attr ( 'href' ) . substr ( 1 ) ) ;
}
} ) ;
window . addEventListener ( "popstate" , function ( e ) {
var activeTab = $ ( '[href=' + location . hash + ']' ) ;
if ( activeTab . length ) {
activeTab . tab ( 'show' ) ;
} else {
$ ( '.nav-tabs a:first' ) . tab ( 'show' ) ;
}
} ) ;
for ( i = 1 ; i < 3 ; i ++ ) {
$ ( ".pubkeyAdd" ) . click ( ) ;
}
validateOutputAmount ( ) ;
2014-12-31 14:33:22 +01:00
2015-06-24 00:34:30 +02:00
/* settings page code */
$ ( "#coinjs_pub" ) . val ( '0x' + ( coinjs . pub ) . toString ( 16 ) ) ;
$ ( "#coinjs_priv" ) . val ( '0x' + ( coinjs . priv ) . toString ( 16 ) ) ;
$ ( "#coinjs_multisig" ) . val ( '0x' + ( coinjs . multisig ) . toString ( 16 ) ) ;
$ ( "#coinjs_hdpub" ) . val ( '0x' + ( coinjs . hdkey . pub ) . toString ( 16 ) ) ;
$ ( "#coinjs_hdprv" ) . val ( '0x' + ( coinjs . hdkey . prv ) . toString ( 16 ) ) ;
$ ( "#settingsBtn" ) . click ( function ( ) {
2015-08-14 23:07:19 +02:00
// log out of openwallet
$ ( "#walletLogout" ) . click ( ) ;
2015-06-24 00:34:30 +02:00
$ ( "#statusSettings" ) . removeClass ( "alert-success" ) . removeClass ( "alert-danger" ) . addClass ( "hidden" ) . html ( "" ) ;
$ ( "#settings .has-error" ) . removeClass ( "has-error" ) ;
$ . each ( $ ( ".coinjssetting" ) , function ( i , o ) {
if ( ! $ ( o ) . val ( ) . match ( /^0x[0-9a-f]+$/ ) ) {
$ ( o ) . parent ( ) . addClass ( "has-error" ) ;
}
} ) ;
if ( $ ( "#settings .has-error" ) . length == 0 ) {
coinjs . pub = $ ( "#coinjs_pub" ) . val ( ) * 1 ;
coinjs . priv = $ ( "#coinjs_priv" ) . val ( ) * 1 ;
coinjs . multisig = $ ( "#coinjs_multisig" ) . val ( ) * 1 ;
coinjs . hdkey . pub = $ ( "#coinjs_hdpub" ) . val ( ) * 1 ;
coinjs . hdkey . prv = $ ( "#coinjs_hdprv" ) . val ( ) * 1 ;
configureBroadcast ( ) ;
configureGetUnspentTx ( ) ;
$ ( "#statusSettings" ) . addClass ( "alert-success" ) . removeClass ( "hidden" ) . html ( "<span class=\"glyphicon glyphicon-ok\"></span> Settings updates successfully" ) . fadeOut ( ) . fadeIn ( ) ;
} else {
$ ( "#statusSettings" ) . addClass ( "alert-danger" ) . removeClass ( "hidden" ) . html ( "There is an error with one or more of your settings" ) ;
}
} ) ;
$ ( "#coinjs_coin" ) . change ( function ( ) {
var o = ( $ ( "option:selected" , this ) . attr ( "rel" ) ) . split ( ";" ) ;
// deal with broadcasting settings
if ( o [ 5 ] == "false" ) {
$ ( "#coinjs_broadcast, #rawTransaction, #rawSubmitBtn, #openBtn" ) . attr ( 'disabled' , true ) ;
$ ( "#coinjs_broadcast" ) . val ( "coinb.in" ) ;
} else {
$ ( "#coinjs_broadcast" ) . val ( o [ 5 ] ) ;
$ ( "#coinjs_broadcast, #rawTransaction, #rawSubmitBtn, #openBtn" ) . attr ( 'disabled' , false ) ;
}
// deal with unspent output settings
if ( o [ 6 ] == "false" ) {
$ ( "#coinjs_utxo, #redeemFrom, #redeemFromBtn, #openBtn, .qrcodeScanner" ) . attr ( 'disabled' , true ) ;
$ ( "#coinjs_utxo" ) . val ( "coinb.in" ) ;
} else {
$ ( "#coinjs_utxo" ) . val ( o [ 6 ] ) ;
$ ( "#coinjs_utxo, #redeemFrom, #redeemFromBtn, #openBtn, .qrcodeScanner" ) . attr ( 'disabled' , false ) ;
}
// deal with the reset
$ ( "#coinjs_pub" ) . val ( o [ 0 ] ) ;
2015-06-24 01:12:09 +02:00
$ ( "#coinjs_priv" ) . val ( o [ 1 ] ) ;
2015-06-24 00:34:30 +02:00
$ ( "#coinjs_multisig" ) . val ( o [ 2 ] ) ;
$ ( "#coinjs_hdpub" ) . val ( o [ 3 ] ) ;
$ ( "#coinjs_hdprv" ) . val ( o [ 4 ] ) ;
// hide/show custom screen
if ( $ ( "option:selected" , this ) . val ( ) == "custom" ) {
$ ( "#settingsCustom" ) . removeClass ( "hidden" ) ;
} else {
$ ( "#settingsCustom" ) . addClass ( "hidden" ) ;
}
} ) ;
function configureBroadcast ( ) {
var host = $ ( "#coinjs_broadcast option:selected" ) . val ( ) ;
$ ( "#rawSubmitBtn" ) . unbind ( "" ) ;
2015-08-14 23:07:19 +02:00
if ( host == "blockr.io_litecoin" ) {
2015-06-24 00:34:30 +02:00
$ ( "#rawSubmitBtn" ) . click ( function ( ) {
2015-08-14 23:07:19 +02:00
rawSubmitBlockrio _litecoin ( this )
2015-06-24 00:34:30 +02:00
} ) ;
} else if ( host == "blockr.io_bitcoinmainnet" ) {
$ ( "#rawSubmitBtn" ) . click ( function ( ) {
rawSubmitBlockrio _BitcoinMainnet ( this ) ;
} ) ;
2016-03-16 00:47:40 +01:00
} else if ( host == "chain.so_bitcoinmainnet" ) {
$ ( "#rawSubmitBtn" ) . click ( function ( ) {
rawSubmitChainso _BitcoinMainnet ( this ) ;
} ) ;
2016-03-21 14:34:19 +01:00
} else if ( host == "blockcypher_bitcoinmainnet" ) {
$ ( "#rawSubmitBtn" ) . click ( function ( ) {
rawSubmitblockcypher _BitcoinMainnet ( this ) ;
} ) ;
2015-06-24 00:34:30 +02:00
} else {
$ ( "#rawSubmitBtn" ) . click ( function ( ) {
rawSubmitDefault ( this ) ; // revert to default
} ) ;
}
}
function configureGetUnspentTx ( ) {
2015-08-14 23:07:19 +02:00
$ ( "#redeemFromBtn" ) . attr ( 'rel' , $ ( "#coinjs_utxo option:selected" ) . val ( ) ) ;
2015-06-24 00:34:30 +02:00
}
2014-12-31 14:33:22 +01:00
/* capture mouse movement to add entropy */
var IE = document . all ? true : false // Boolean, is browser IE?
if ( ! IE ) document . captureEvents ( Event . MOUSEMOVE )
document . onmousemove = getMouseXY ;
function getMouseXY ( e ) {
var tempX = 0 ;
var tempY = 0 ;
if ( IE ) { // If browser is IE
2014-12-31 20:18:51 +01:00
tempX = event . clientX + document . body . scrollLeft ;
tempY = event . clientY + document . body . scrollTop ;
2014-12-31 14:33:22 +01:00
} else {
2014-12-31 20:18:51 +01:00
tempX = e . pageX ;
tempY = e . pageY ;
2014-12-31 14:33:22 +01:00
} ;
2014-12-31 20:18:51 +01:00
2014-12-31 14:33:22 +01:00
if ( tempX < 0 ) { tempX = 0 } ;
if ( tempY < 0 ) { tempY = 0 } ;
2014-12-31 19:06:24 +01:00
var xEnt = Crypto . util . bytesToHex ( [ tempX ] ) . slice ( - 2 ) ;
var yEnt = Crypto . util . bytesToHex ( [ tempY ] ) . slice ( - 2 ) ;
2014-12-31 14:33:22 +01:00
var addEnt = xEnt . concat ( yEnt ) ;
2014-12-31 20:18:51 +01:00
2014-12-31 14:33:22 +01:00
if ( $ ( "#entropybucket" ) . html ( ) . indexOf ( xEnt ) == - 1 && $ ( "#entropybucket" ) . html ( ) . indexOf ( yEnt ) == - 1 ) {
$ ( "#entropybucket" ) . html ( addEnt + $ ( "#entropybucket" ) . html ( ) ) ;
} ;
2014-12-31 20:18:51 +01:00
if ( $ ( "#entropybucket" ) . html ( ) . length > 128 ) {
$ ( "#entropybucket" ) . html ( $ ( "#entropybucket" ) . html ( ) . slice ( 0 , 128 ) )
} ;
2014-12-31 14:33:22 +01:00
return true ;
} ;
2014-12-02 00:36:49 +01:00
} ) ;