diff --git a/LICENSE b/LICENSE index cf457637..2e6aa30c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,20 +1,3 @@ -The MIT License (MIT) - Copyright (c) 2014 OutCast3k - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +Copyright (c) 2015 ttutdxh.nubits@gmail.com +Copyright (c) 2016 Triplex diff --git a/README.md b/README.md index dd4e44a1..bcf5522b 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,11 @@ -coinbin +Cointoolkit ======= -A Open Source Browser Based Bitcoin Wallet. Version 1.2 beta by OutCast3k +A Open Source Browser Based Bitcoin Wallet. -Live version available at http://coinb.in/ or http://4zpinp6gdkjfplhk.onion +Live version available at http://triplexfw/coinbin/ -Github URL: https://github.com/OutCast3k/coinbin/ - -Coinb.in supports a number of key features such as: +Github URL: https://github.com/triplexfw/coinbin - Offline Compressed & uncompressed Address creation. - Offline Multisignature Address creation. @@ -28,4 +26,4 @@ Coinb.in supports a number of key features such as: - HD (bip32) support - Supports altcoins such as litecoin -Donate to 1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg to see more development! +Donate to BTC: 1J9Lfaz9poYrNSRH1vccd9qeYxBzwZ1Pq7 or DASH: XdR8hW2ac1MtRKNpfBaCzkKJM6P23qju6N to see more development! diff --git a/css/jquery-ui-sort-only.min.css b/css/jquery-ui-sort-only.min.css new file mode 100644 index 00000000..dd15d34f --- /dev/null +++ b/css/jquery-ui-sort-only.min.css @@ -0,0 +1,6 @@ +/*! jQuery UI - v1.11.4 - 2016-01-02 +* http://jqueryui.com +* Includes: core.css, sortable.css +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-sortable-handle{-ms-touch-action:none;touch-action:none} \ No newline at end of file diff --git a/css/style.css b/css/style.css index 9cebfa22..05d8a7ea 100644 --- a/css/style.css +++ b/css/style.css @@ -24,3 +24,46 @@ body { background-color: #f5f5f5; padding-top: 20px; } + +.glyphicon-refresh-animate { + -animation: spin 1s infinite linear; + -webkit-animation: spin2 1s infinite linear; +} + +@-webkit-keyframes spin2 { + from { -webkit-transform: rotate(0deg);} + to { -webkit-transform: rotate(360deg);} +} + +@keyframes spin { + from { transform: scale(1) rotate(0deg);} + to { transform: scale(1) rotate(360deg);} +} + +#verifyTransactionData .table>tbody>tr>td { + vertical-align: middle; +} + +@media (min-width: 768px) { + .wideModal .modal-dialog { + width: 70%; + } +} + +.sig_position { + text-align: center; +} + +#multisigPubKeys .item { + margin-bottom: 5px; +} + +.glyphicon-minus:before { + content: "\2212"; + margin-left: -1px; +} + +.handle { + padding-left: 15px; + font-size: 20px; +} \ No newline at end of file diff --git a/index.html b/index.html index 9f7d4d0f..e4bb045a 100644 --- a/index.html +++ b/index.html @@ -2,19 +2,21 @@ - Bitcoin Wallet by Coinb.in + Cointoolkit - + - + + + @@ -30,7 +32,9 @@ - + + + @@ -45,27 +49,38 @@ - + Cointoolkit @@ -79,14 +94,14 @@
-

Coinb.in Welcome to the Blockchain

+

Cointoolkit Welcome to the Blockchain

-

Bitcoin. It's your money!

-

Be your own bank, take control of your own money and start using Bitcoin today!

-

Learn more »

+

Cointoolkit

+

Be your own bank, take control of your own money and start using DASH today!

+

Create new address »


@@ -94,16 +109,16 @@

Bitcoin. It's your money!

Open Source

-

Coinbin is an open source web based wallet written in javascript and released under the MIT license which means its free to use and edit.

+

Cointoolkit is an open source web based wallet written in javascript and released under the MIT license which means it's free to use and edit.

MultiSig

-

We offer a fully transparent multisig solution which works seamlessly offline and with other bitcoin clients.

+

This is the first tool that supports combining signatures in a multi signature transaction. Verify your first transaction, click the number of signatures and combine the other versions

-

Raw Transactions

+

Raw Transactions

Create, verify, sign and broadcast custom raw transactions online with advanced features and minimal effort!

@@ -121,7 +136,7 @@

Addresses

Development

-

Use what we've built to write your own projects! See our documention (coming soon), or contribute at github.

+

Use what we've built to write your own projects! See our documention (coming soon), or contribute at github.

@@ -129,7 +144,7 @@

Development

-

Open Wallet browser based bitcoin wallet

+

Open Wallet browser based wallet

@@ -218,7 +233,7 @@

Open Wallet browser based bitcoin wallet

- +
@@ -236,24 +251,41 @@

Open Wallet browser based bitcoin wallet

+ +
+

QR Code Generator transfer data easily between devices

+

You can store anything from an address to a entire transaction or a private key

+ +
+
+ +
+
+
-
-

New Address create a new address

-

Any keys used you will need to manually store safely as they will be needed later to redeem the bitcoins.

- +
+ +
+
+
+
+

Create new address

+

Any keys used you will need to manually store safely as they will be needed later to redeem the coins.

+ +
- +
- +
- + @@ -263,6 +295,14 @@

New Address create a new address

+ + +
+ + + + +

Address Options

You can use the advanced options below to generate different kind of keys and addresses.

@@ -270,8 +310,11 @@

Address Options

- - + +
@@ -304,7 +347,7 @@

New Multisig Address Secure multisig address

-

Public keys can be generated in your browser or from your bitcoin client.

+

Public keys can be generated in your browser or from your wallet.

Enter the public keys of all the participants, to create a multi signature address. Maximum of 15 allowed. Compressed and uncompressed public keys are accepted.

@@ -316,14 +359,38 @@

New Multisig Address Secure multisig address

-
-
-
- -
- -

-
+
+ + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +

Enter the amount of signatures required to release the coins

@@ -367,13 +434,15 @@

New Multisig Address Secure multisig address

-

This script should be saved and should be shared with all the participants before a payment is made, so they may validate the authenticity of the address, it will also be used later to release the bitcoins.

+

This script should be saved and should be shared with all the participants before a payment is made, so they may validate the authenticity of the address, it will also be used later to release the coins.

+ Or +
@@ -409,7 +478,7 @@

Address Options

-

Transaction Create a new transaction

+

New Transaction Create a new transaction

Use this page to create a raw transaction

Address, WIF key or Multisig Redeem Script: @@ -454,7 +523,14 @@

Transaction Create a new transaction


+ +
+ +

Indicates the timestamp of a transaction.

+ +
+

The settings page can be used to select alternative networks of which you can retrieve your unspent outputs and broadcast a signed transaction into.

@@ -474,24 +550,30 @@

Transaction Create a new transaction

Enter the address and amount you wish to make a payment to.

-
+
-
+
+
+ +
-
- +
+
-
+
+
+ +
@@ -535,7 +617,7 @@

Transaction Create a new transaction

- +
@@ -562,12 +644,22 @@

Transaction Create a new transaction

The transaction below has been generated and encoded. It can be broadcasted once it has been signed.


- - -

Size: 0 bytes

+ +
+
+

Size: 0 bytes

+
+ If you are sure: + +
+
+
- +
@@ -584,57 +676,136 @@

Verify transactions and other scripts

+ + + + + diff --git a/js/coin.js b/js/coin.js index 25536d3c..75afdd51 100644 --- a/js/coin.js +++ b/js/coin.js @@ -1,8 +1,8 @@ /* - Coinjs 0.01 beta by OutCast3k{at}gmail.com - A bitcoin frameworkcoinjs. + Framework to work with bitcoin-like transactions. + Adapted to Peershares assets by ttutdxh.nubits@gmail.com https://github.com/ttutdxh-nubits/ - http://github.com/OutCast3k/coinjs or http://coinb.in/coinjs + Originally by http://github.com/OutCast3k/coinjs */ (function () { @@ -10,26 +10,186 @@ var coinjs = window.coinjs = function () { }; /* public vars */ + coinjs.debug = false; + + /* Bitcoin by default */ coinjs.pub = 0x00; coinjs.priv = 0x80; coinjs.multisig = 0x05; coinjs.hdkey = {'prv':0x0488ade4, 'pub':0x0488b21e}; + + coinjs.txExtraTimeField = false; + coinjs.txExtraTimeFieldValue = false; + coinjs.txExtraUnitField = false; + coinjs.txExtraUnitFieldValue = false; + + coinjs.decimalPlaces = 8; + coinjs.symbol = 'BTC'; + coinjs.compressed = false; - /* other vars */ - coinjs.developer = '1CWHWkTWaq1K5hevimJia3cyinQsrgXUvg'; // bitcoin + coinjs.opcode = { + // push value + OP_FALSE : 0, + OP_0 : 0, + OP_PUSHDATA1 : 76, + OP_PUSHDATA2 : 77, + OP_PUSHDATA4 : 78, + OP_1NEGATE : 79, + OP_RESERVED : 80, + OP_1 : 81, + OP_TRUE : 81, + OP_2 : 82, + OP_3 : 83, + OP_4 : 84, + OP_5 : 85, + OP_6 : 86, + OP_7 : 87, + OP_8 : 88, + OP_9 : 89, + OP_10 : 90, + OP_11 : 91, + OP_12 : 92, + OP_13 : 93, + OP_14 : 94, + OP_15 : 95, + OP_16 : 96, + + // control + OP_NOP : 97, + OP_VER : 98, + OP_IF : 99, + OP_NOTIF : 100, + OP_VERIF : 101, + OP_VERNOTIF : 102, + OP_ELSE : 103, + OP_ENDIF : 104, + OP_VERIFY : 105, + OP_RETURN : 106, + + // stack ops + OP_TOALTSTACK : 107, + OP_FROMALTSTACK : 108, + OP_2DROP : 109, + OP_2DUP : 110, + OP_3DUP : 111, + OP_2OVER : 112, + OP_2ROT : 113, + OP_2SWAP : 114, + OP_IFDUP : 115, + OP_DEPTH : 116, + OP_DROP : 117, + OP_DUP : 118, + OP_NIP : 119, + OP_OVER : 120, + OP_PICK : 121, + OP_ROLL : 122, + OP_ROT : 123, + OP_SWAP : 124, + OP_TUCK : 125, + + // splice ops + OP_CAT : 126, + OP_SUBSTR : 127, + OP_LEFT : 128, + OP_RIGHT : 129, + OP_SIZE : 130, + + // bit logic + OP_INVERT : 131, + OP_AND : 132, + OP_OR : 133, + OP_XOR : 134, + OP_EQUAL : 135, + OP_EQUALVERIFY : 136, + OP_RESERVED1 : 137, + OP_RESERVED2 : 138, + + // numeric + OP_1ADD : 139, + OP_1SUB : 140, + OP_2MUL : 141, + OP_2DIV : 142, + OP_NEGATE : 143, + OP_ABS : 144, + OP_NOT : 145, + OP_0NOTEQUAL : 146, + + OP_ADD : 147, + OP_SUB : 148, + OP_MUL : 149, + OP_DIV : 150, + OP_MOD : 151, + OP_LSHIFT : 152, + OP_RSHIFT : 153, + + OP_BOOLAND : 154, + OP_BOOLOR : 155, + OP_NUMEQUAL : 156, + OP_NUMEQUALVERIFY : 157, + OP_NUMNOTEQUAL : 158, + OP_LESSTHAN : 159, + OP_GREATERTHAN : 160, + OP_LESSTHANOREQUAL : 161, + OP_GREATERTHANOREQUAL : 162, + OP_MIN : 163, + OP_MAX : 164, + + OP_WITHIN : 165, + + // crypto + OP_RIPEMD160 : 166, + OP_SHA1 : 167, + OP_SHA256 : 168, + OP_HASH160 : 169, + OP_HASH256 : 170, + OP_CODESEPARATOR : 171, + OP_CHECKSIG : 172, + OP_CHECKSIGVERIFY : 173, + OP_CHECKMULTISIG : 174, + OP_CHECKMULTISIGVERIFY : 175, + + // expansion + OP_NOP1 : 176, + OP_NOP2 : 177, + OP_NOP3 : 178, + OP_NOP4 : 179, + OP_NOP5 : 180, + OP_NOP6 : 181, + OP_NOP7 : 182, + OP_NOP8 : 183, + OP_NOP9 : 184, + OP_NOP10 : 185, + + // template matching params + OP_PUBKEYHASH : 253, + OP_PUBKEY : 254, + OP_INVALIDOPCODE : 255 + }; + + coinjs.reverseOpcode = []; + + for (var opcode in coinjs.opcode) { + coinjs.reverseOpcode[coinjs.opcode[opcode]] = opcode; + } - /* bit(coinb.in) api vars */ - coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+'coinb.in/api/'; - coinjs.uid = '1'; - coinjs.key = '12345678901234567890123456789012'; /* start of address functions */ /* generate a private and public keypair, with address and WIF address */ - coinjs.newKeys = function(input){ - var privkey = (input) ? Crypto.SHA256(input) : this.newPrivkey(); + coinjs.newKeys = function(input, isPrivKey){ + if (input == "" || (isPrivKey && !input.match(/^[a-f0-9]{64}$/gi))) { + var message = (input == "")?'Empty seed':'Invalid private key'; + return { + 'privkey': message, + 'pubkey': message, + 'address': message, + 'wif': message, + 'compressed': message, + }; + } + var privkey = (input) ? ((isPrivKey)?input:Crypto.SHA256(input)) : this.newPrivkey(); var pubkey = this.newPubkey(privkey); return { 'privkey': privkey, @@ -50,7 +210,7 @@ x += window.history.length; x += coinjs.random(64); x += navigator.userAgent; - x += 'coinb.in'; + x += 'cointoolkit'; x += (Crypto.util.randomBytes(64)).join(""); x += x.length; var dateObj = new Date(); @@ -100,16 +260,13 @@ /* provide a public key and return address */ coinjs.pubkey2address = function(h){ var r = ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(h), {asBytes: true})); - r.unshift(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)); + return coinjs.scripthash2address(Crypto.util.bytesToHex(r), coinjs.pub); } /* provide a scripthash and return address */ - coinjs.scripthash2address = function(h){ + coinjs.scripthash2address = function(h, type){ var x = Crypto.util.hexToBytes(h); - x.unshift(coinjs.pub); + x.unshift(type); var r = x; r = Crypto.SHA256(Crypto.SHA256(r,{asBytes: true}),{asBytes: true}); var checksum = r.slice(0,4); @@ -125,14 +282,12 @@ } s.writeOp(81 + pubkeys.length - 1); //OP_1 s.writeOp(174); //OP_CHECKMULTISIG + 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}; + + return {'address':coinjs.scripthash2address(Crypto.util.bytesToHex(x), coinjs.multisig), 'scriptHash':Crypto.util.bytesToHex(x), 'redeemScript':redeemScript}; } /* provide a privkey and return an WIF */ @@ -229,7 +384,8 @@ o.prefix = front.slice(71); } else { // everything else - o.type = 'other'; // address is still valid but unknown version + //- invalid -// o.type = 'other'; // address is still valid but unknown version + return false; } return o; @@ -237,15 +393,11 @@ return false; } } catch(e) { + if (coinjs.debug) {console.log(e.stack)}; return false; } } - /* retreive the balance from a given address */ - coinjs.addressBalance = function(address, callback){ - coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=bal&address='+address+'&r='+Math.random(), callback, "GET"); - } - /* decompress an compressed public key */ coinjs.pubkeydecompress = function(pubkey) { var curve = EllipticCurve.getSECCurveByName("secp256k1"); @@ -259,7 +411,7 @@ publicKeyBytes.unshift(0x04); return Crypto.util.bytesToHex(publicKeyBytes); } catch (e) { - // console.log(e); + if (coinjs.debug) {console.log(e.stack)}; return false; } } @@ -649,9 +801,10 @@ r.pubkeys = pubkeys; var multi = coinjs.pubkeys2MultisigAddress(pubkeys, r.signaturesRequired); r.address = multi['address']; + r.scriptHash = multi['scriptHash']; } } catch(e) { - // console.log(e); + if (coinjs.debug) {console.log(e.stack)}; r = false; } return r; @@ -661,7 +814,7 @@ r.spendToScript = function(address){ var addr = coinjs.addressDecode(address); var s = coinjs.script(); - if(addr.version==5){ // multisig address + if(addr.type=="multisig"){ // multisig address s.writeOp(169); //OP_HASH160 s.writeBytes(addr.bytes); s.writeOp(135); //OP_EQUAL @@ -717,6 +870,27 @@ return true; } + /* convert to opcodes */ + r.toASM = function() { + var s = ''; + + for (var i = 0; i < this.chunks.length; i++) { + var chunk = this.chunks[i]; + + if (i > 0) { + s += ' '; + } + + if (Array.isArray(chunk)) { + s += Crypto.util.bytesToHex(chunk); + } else { + s += coinjs.reverseOpcode[chunk]; + } + } + + return s; + } + r.parse(); return r; } @@ -733,6 +907,9 @@ r.outs = []; r.timestamp = null; r.block = null; + + r.nTime = 0; + r.nUnit = 0; /* add an input to a transaction */ r.addinput = function(txid, index, script){ @@ -746,7 +923,7 @@ /* add an output to a transaction */ r.addoutput = function(address, value){ var o = {}; - o.value = new BigInteger('' + Math.round((value*1) * 1e8), 10); + o.value = new BigInteger('' + Math.round((value*1) * ("1e"+coinjs.decimalPlaces)), 10); var s = coinjs.script(); o.script = s.spendToScript(address); @@ -786,7 +963,7 @@ this.outs.push(v); var o = {}; - o.value = new BigInteger('' + Math.round((value*1) * 1e8), 10); + o.value = new BigInteger('' + Math.round((value*1) * ("1e"+coinjs.decimalPlaces)), 10); var s = coinjs.script(); o.script = s.spendToScript(sendaddress); @@ -808,15 +985,10 @@ return r; } - /* list unspent transactions */ - r.listUnspent = function(address, callback) { - coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=unspent&address='+address+'&r='+Math.random(), callback, "GET"); - } - /* add unspent to transaction */ r.addUnspent = function(address, callback){ var self = this; - this.listUnspent(address, function(data){ + /*this.listUnspent(address, function(data){ TODO: not available anymore var s = coinjs.script(); var pubkeyScript = s.pubkeyHash(address); var value = 0; @@ -850,7 +1022,7 @@ x.value = value; x.total = total; return callback(x); - }); + });*/ } /* add unspent and sign */ @@ -863,12 +1035,6 @@ }); } - /* broadcast a transaction */ - r.broadcast = function(callback, txhex){ - var tx = txhex || this.serialize(); - coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=bitcoin&request=sendrawtransaction&rawtx='+tx+'&r='+Math.random(), callback, "GET"); - } - /* generate the transaction hash to sign from a transaction input */ r.transactionHash = function(index) { var clone = coinjs.clone(this); @@ -903,7 +1069,14 @@ return {'type':'scriptpubkey', 'signed':'true', 'signatures':1, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)}; } 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])}; + + var count = -1; // To account for serialized redeemScript + for (var i = 0; i < this.ins[index].script.chunks.length; i++) { + if(this.ins[index].script.chunks[i]){ // omit 0 signature placeholder + ++count; + } + } + return {'type':'multisig', 'signed':'true', 'signatures':count, 'script': Crypto.util.bytesToHex(this.ins[index].script.chunks[this.ins[index].script.chunks.length-1])}; } else if (this.ins[index].script.chunks[0]>=80 && this.ins[index].script.chunks[this.ins[index].script.chunks.length-1]==174) { // OP_CHECKMULTISIG // multisig script, without signature! return {'type':'multisig', 'signed':'false', 'signatures':0, 'script': Crypto.util.bytesToHex(this.ins[index].script.buffer)}; @@ -1049,47 +1222,58 @@ return true; } - /* sign a multisig input */ - r.signmultisig = function(index, wif){ - - function scriptListPubkey(redeemScript){ - var r = {}; - for(var i=1;i=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'; - s += (s+''+s); - - for(i=0;i<=50;i++){ - s = Crypto.SHA256(s); - } - - coinjs.compressed = true; - var keys = coinjs.newKeys(s); - - $("#walletAddress").html(keys.address); - $("#walletHistory").attr('href','https://btc.blockr.io/address/info/'+keys.address); - - $("#walletQrCode").html(""); - var qrcode = new QRCode("walletQrCode"); - qrcode.makeCode("bitcoin:"+keys.address); - - $("#walletKeys .privkey").val(keys.wif); - $("#walletKeys .pubkey").val(keys.pubkey); - $("#walletKeys .privkeyaes").val(CryptoJS.AES.encrypt(keys.wif, pass)); - - $("#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(' '); - }); - - $("#walletLogout").click(function(){ - $("#openEmail").val(""); - $("#openPass").val(""); - $("#openPassConfirm").val(""); - - $("#openLogin").show(); - $("#openWallet").addClass("hidden").show(); - - $("#walletAddress").html(""); - $("#walletHistory").attr('href','https://btc.blockr.io/address/info/'); - - $("#walletQrCode").html(""); - var qrcode = new QRCode("walletQrCode"); - qrcode.makeCode("bitcoin:"); - - $("#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); - total += amount.val()*1; - tx.addoutput(addr.val(), amount.val()*1); - }); - - thisbtn.attr('disabled',true); - - tx.addUnspent($("#walletAddress").html(), function(data){ - var dvalue = data.value/100000000 - if(dvalue>=total){ - var change = dvalue-total; - if(change>0){ - 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,' ')); - thisbtn.attr('disabled',false); - } - - // 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(); - thisbtn.attr('disabled',false); - } - - $("#walletLoader").addClass("hidden"); - }); - }); - - $("#walletSendBtn").click(function(){ - - $("#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(' One or more input has an error'); - } - }); - - $("#walletShowSpend").click(function(){ - $("#walletSpend").removeClass("hidden"); - $("#walletKeys").removeClass("hidden").addClass("hidden"); - }); - - $("#walletSpendTo .addressAdd").click(function(){ - var clone = '
'+$(this).parent().html()+'
'; - $("#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); - - /* encrypted key code */ - if((!$("#encryptKey").is(":checked")) || $("#aes256pass").val()==$("#aes256pass_confirm").val()){ - $("#aes256passStatus").addClass("hidden"); - if($("#encryptKey").is(":checked")){ - $("#aes256wifkey").removeClass("hidden"); - } - } else { - $("#aes256passStatus").removeClass("hidden"); - } - $("#newPrivKeyEnc").val(CryptoJS.AES.encrypt(coin.wif, $("#aes256pass").val())+''); - - }); - - $("#newBrainwallet").click(function(){ - if($(this).is(":checked")){ - $("#brainwallet").removeClass("hidden"); - } else { - $("#brainwallet").addClass("hidden"); - } - }); - - $("#encryptKey").click(function(){ - if($(this).is(":checked")){ - $("#aes256passform").removeClass("hidden"); - } else { - $("#aes256wifkey, #aes256passform, #aes256passStatus").addClass("hidden"); - } - }); - - /* 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(' 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']); - $("#multiSigData .scriptUrl").val(document.location.origin+''+document.location.pathname+'?verify='+multisig['redeemScript']+'#verify'); - $("#multiSigData").removeClass('hidden').addClass('show').fadeIn(); - $("#releaseCoins").removeClass('has-error'); - } else { - $("#multiSigErrorMsg").html(' One or more public key is invalid!').fadeIn(); - } - }); - - $("#multisigPubKeys .pubkeyAdd").click(function(){ - if($("#multisigPubKeys .pubkeyRemove").length<14){ - var clone = '
'+$(this).parent().html()+'
'; - $("#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(); - }); - } - }); - - $("#mediatorList").change(function(){ - var data = ($(this).val()).split(";"); - $("#mediatorPubkey").val(data[0]); - $("#mediatorEmail").val(data[1]); - $("#mediatorFee").val(data[2]); - }).change(); - - $("#mediatorAddKey").click(function(){ - var count = 0; - var len = $(".pubkeyRemove").length; - if(len<14){ - $.each($("#multisigPubKeys .pubkey"),function(i,o){ - if($(o).val()==''){ - $(o).val($("#mediatorPubkey").val()).fadeOut().fadeIn(); - $("#mediatorClose").click(); - return false; - } else if(count==len){ - $("#multisigPubKeys .pubkeyAdd").click(); - $("#mediatorAddKey").click(); - return false; - } - count++; - }); - - $("#mediatorClose").click(); - } - }); - - /* new -> 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"); - } - }); - - /* new -> transaction code */ - - $("#recipients .addressAddTo").click(function(){ - if($("#recipients .addressRemoveTo").length<19){ - var clone = '

'+$(this).parent().parent().html()+'
'; - $("#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 = '

'+$(this).parent().parent().html()+'
'; - $("#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(); - - $("#transactionCreate, #transactionCreateStatus").addClass("hidden"); - - if(($("#nLockTime").val()).match(/^[0-9]+$/g)){ - tx.lock_time = $("#nLockTime").val()*1; - } - - $("#inputs .row").removeClass('has-error'); - - $('#putTabs a[href="#txinputs"], #putTabs a[href="#txoutputs"]').attr('style',''); - - $.each($("#inputs .row"), function(i,o){ - if(!($(".txId",o).val()).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")){ - tx.addinput($(".txId",o).val(), $(".txIdN",o).val(), $(".txIdScript",o).val()); - } else { - $('#putTabs a[href="#txinputs"]').attr('style','color:#a94442;'); - } - }); - - $("#recipients .row").removeClass('has-error'); - - $.each($("#recipients .row"), function(i,o){ - var a = ($(".address",o).val()); - var ad = coinjs.addressDecode(a); - if(((a!="") && (ad.version == coinjs.pub || ad.version == coinjs.multisig)) && $(".amount",o).val()!=""){ // address - tx.addoutput(a, $(".amount",o).val()); - } else if (((a!="") && ad.version === 42) && $(".amount",o).val()!=""){ // stealth address - tx.addstealth(ad, $(".amount",o).val()); - } else if (((($("#opReturn").is(":checked")) && a.match(/^[a-f0-9]+$/ig)) && a.length<160) && (a.length%2)==0) { // data - tx.adddata(a); - } else { // neither address nor data - $(o).addClass('has-error'); - $('#putTabs a[href="#txoutputs"]').attr('style','color:#a94442;'); - } - }); - - - if(!$("#recipients .row, #inputs .row").hasClass('has-error')){ - $("#transactionCreate textarea").val(tx.serialize()); - $("#transactionCreate .txSize").html(tx.size()); - - $("#transactionCreate").removeClass("hidden"); - - if($("#transactionFee").val()>=0.01){ - $("#modalWarningFeeAmount").html($("#transactionFee").val()); - $("#modalWarningFee").modal("show"); - } - } else { - $("#transactionCreateStatus").removeClass("hidden").html("One or more input or output is invalid").fadeOut().fadeIn(); - } - }); - - $(".txidClear").click(function(){ - $("#inputs .row:first input").attr('disabled',false); - $("#inputs .row:first input").val(""); - totalInputAmount(); - }); - - $("#inputs .txIdAmount").unbind("").change(function(){ - totalInputAmount(); - }).keyup(function(){ - totalInputAmount(); - }); - - /* code for the qr code scanner */ - - $(".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"); - } - } - }); - - $("#videoSource").unbind("change").change(function(){ - scannerStart() - }); - - } else { - $("#videoSource").addClass("hidden"); - } - scannerStart(); - $("#qrcode-scanner-callback-to").html($(this).attr('forward-result')); - }); - - function scannerStart(){ - 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"); - } - } - - /* redeem from button code */ - - $("#redeemFromBtn").click(function(){ - var redeem = redeemingFrom($("#redeemFrom").val()); - - $("#redeemFromStatus, #redeemFromAddress").addClass('hidden'); - - if(redeem.from=='multisigAddress'){ - $("#redeemFromStatus").removeClass('hidden').html(' You should use the redeem script, not the multisig address!'); - return false; - } - - if(redeem.from=='other'){ - $("#redeemFromStatus").removeClass('hidden').html(' 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'){ - listUnspentBlockrio_BitcoinMainnet(redeem); - } else if(host=='chain.so_litecoin'){ - listUnspentChainso_Litecoin(redeem); - } else { - listUnspentDefault(redeem); - } - }); - - /* function to determine what we are redeeming from */ - function redeemingFrom(string){ - var r = {}; - var decode = coinjs.addressDecode(string); - if(decode.version == coinjs.pub){ // regular address - r.addr = string; - r.from = 'address'; - r.isMultisig = false; - } else if (decode.version == coinjs.priv){ // wif key - var a = coinjs.wif2address(string); - r.addr = a['address']; - r.from = 'wif'; - r.isMultisig = false; - } else if (decode.version == coinjs.multisig){ // mulisig address - r.addr = ''; - r.from = 'multisigAddress'; - r.isMultisig = false; - } else { - var script = coinjs.script(); - var decodeRs = script.decodeRedeemScript(string); - if(decodeRs){ // redeem script - r.addr = decodeRs['address']; - r.from = 'redeemScript'; - r.decodedRs = decodeRs; - r.isMultisig = true; - } else { // something else - r.addr = ''; - r.from = 'other'; - r.isMultisig = false; - } - } - return r; - } - - /* mediator payment code for when you used a public key */ - function mediatorPayment(redeem){ - - if(redeem.from=="redeemScript"){ - - $('#recipients .row[rel="'+redeem.addr+'"]').parent().remove(); - - $.each(redeem.decodedRs.pubkeys, function(i, o){ - $.each($("#mediatorList option"), function(mi, mo){ - - var ms = ($(mo).val()).split(";"); - - var pubkey = ms[0]; // mediators pubkey - var fee = ms[2]*1; // fee in a percentage - var payto = coinjs.pubkey2address(pubkey); // pay to mediators address - - if(o==pubkey){ // matched a mediators pubkey? - - var clone = '
'+$("#recipients .addressAddTo").parent().parent().html()+'

'; - $("#recipients").prepend(clone); - - $("#recipients .mediator_"+pubkey+" .glyphicon-plus:first").removeClass('glyphicon-plus'); - $("#recipients .mediator_"+pubkey+" .address:first").val(payto).attr('disabled', true).attr('readonly',true).attr('title','Medation fee for '+$(mo).html()); - - var amount = ((fee*$("#totalInput").html())/100).toFixed(8); - $("#recipients .mediator_"+pubkey+" .amount:first").attr('disabled',(((amount*1)==0)?false:true)).val(amount).attr('title','Medation fee for '+$(mo).html()); - } - }); - }); - - validateOutputAmount(); - } - } - - /* global function to add outputs to page */ - function addOutput(tx, n, script, amount) { - if(tx){ - if($("#inputs .txId:last").val()!=""){ - $("#inputs .txidAdd").click(); - } - - $("#inputs .row:last input").attr('disabled',true); - - var 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*/ - function listUnspentDefault(redeem){ - var tx = coinjs.transaction(); - tx.listUnspent(redeem.addr, function(data){ - if(redeem.addr) { - $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); - - $.each($(data).find("unspent").children(), function(i,o){ - var tx = $(o).find("tx_hash").text(); - var n = $(o).find("tx_output_n").text(); - var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : $(o).find("script").text(); - var amount = (($(o).find("value").text()*1)/100000000).toFixed(8); - - addOutput(tx, n, script, amount); - }); - } - - $("#redeemFromBtn").html("Load").attr('disabled',false); - totalInputAmount(); - - mediatorPayment(redeem); - }); - } - - /* retrieve unspent data from blockrio for mainnet */ - function listUnspentBlockrio_BitcoinMainnet(redeem){ - $.ajax ({ - type: "POST", - url: "https://btc.blockr.io/api/v1/address/unspent/"+redeem.addr+"?unconfirmed=1", - dataType: "json", - error: function(data) { - $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs!'); - }, - success: function(data) { - if((data.status && data.data) && data.status=='success'){ - $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); - for(var i in data.data.unspent){ - var o = data.data.unspent[i]; - var tx = o.tx; - var n = o.n; - var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.script; - var amount = o.amount; - addOutput(tx, n, script, amount); - } - } else { - $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); - } - }, - complete: function(data, status) { - $("#redeemFromBtn").html("Load").attr('disabled',false); - totalInputAmount(); - } - }); - } - - /* retrieve unspent data from blockrio for litecoin */ - function listUnspentChainso_Litecoin(redeem){ - $.ajax ({ - type: "GET", - url: "https://chain.so/api/v2/get_tx_unspent/ltc/"+redeem.addr, - dataType: "json", - error: function(data) { - $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs!'); - }, - success: function(data) { - console.log(data); - if((data.status && data.data) && data.status=='success'){ - $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); - for(var i in data.data.txs){ - var o = data.data.txs[i]; - var tx = ((o.txid).match(/.{1,2}/g).reverse()).join("")+''; - var n = o.output_no; - var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.script_hex; - var amount = o.value; - addOutput(tx, n, script, amount); - } - } else { - $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); - } - }, - complete: function(data, status) { - $("#redeemFromBtn").html("Load").attr('disabled',false); - totalInputAmount(); - } - }); - } - - /* math to calculate the inputs and outputs */ - - function totalInputAmount(){ - $("#totalInput").html('0.00'); - $.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'); - } - - $("#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"); - } - }); - - /* broadcast a transaction */ - - $("#rawSubmitBtn").click(function(){ - rawSubmitDefault(this); - }); - - // broadcast transaction vai coinbin (default) - function rawSubmitDefault(btn){ - var thisbtn = btn; - $(thisbtn).val('Please wait, loading...').attr('disabled',true); - $.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(''); - }, - 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(' '); - } - }, - complete: function(data, status) { - $("#rawTransactionStatus").fadeOut().fadeIn(); - $(thisbtn).val('Submit').attr('disabled',false); - } - }); - } - - // 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(''); - }, - success: function(data) { - var obj = $.parseJSON(data.responseText); - if((obj.status && obj.data) && obj.status=='success'){ - $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+obj.data); - } else { - $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend(''); - } - }, - complete: function(data, status) { - $("#rawTransactionStatus").fadeOut().fadeIn(); - $(thisbtn).val('Submit').attr('disabled',false); - } - }); - } - - // broadcast transaction via blockr.io for litecoin - function rawSubmitBlockrio_litecoin(thisbtn){ - $(thisbtn).val('Please wait, loading...').attr('disabled',true); - $.ajax ({ - type: "POST", - url: "https://ltc.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(''); - }, - success: function(data) { - var obj = $.parseJSON(data.responseText); - if((obj.status && obj.data) && obj.status=='success'){ - $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+obj.data); - } else { - $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend(''); - } - }, - complete: function(data, status) { - $("#rawTransactionStatus").fadeOut().fadeIn(); - $(thisbtn).val('Submit').attr('disabled',false); - } - }); - } - - /* verify script code */ - - $("#verifyBtn").click(function(){ - $(".verifyData").addClass("hidden"); - $("#verifyStatus").hide(); - if(!decodeRedeemScript()){ - if(!decodeTransactionScript()){ - if(!decodePrivKey()){ - if(!decodePubKey()){ - if(!decodeHDaddress()){ - $("#verifyStatus").removeClass('hidden').fadeOut().fadeIn(); - } - } - } - } - } - - }); - - function decodeRedeemScript(){ - var script = coinjs.script(); - var decode = script.decodeRedeemScript($("#verifyScript").val()); - if(decode){ - $("#verifyRsData .multisigAddress").val(decode['address']); - $("#verifyRsData .signaturesRequired").html(decode['signaturesRequired']); - $("#verifyRsData table tbody").html(""); - for(var i=0;i').appendTo("#verifyRsData table tbody"); - } - $("#verifyRsData").removeClass("hidden"); - $(".verifyLink").attr('href','?verify='+$("#verifyScript").val()); - return true; - } else { - return false; - } - } - - function decodeTransactionScript(){ - var tx = coinjs.transaction(); - try { - var decode = tx.deserialize($("#verifyScript").val()); - // console.log(decode); - $("#verifyTransactionData .transactionVersion").html(decode['version']); - $("#verifyTransactionData .transactionSize").html(decode.size()+' bytes'); - $("#verifyTransactionData .transactionLockTime").html(decode['lock_time']); - $("#verifyTransactionData").removeClass("hidden"); - $("#verifyTransactionData tbody").html(""); - - var h = ''; - $.each(decode.ins, function(i,o){ - var s = decode.extractScriptKey(i); - h += ''; - h += ''; - h += ''+o.outpoint.index+''; - h += ''; - h += ' '; - if(s['type']=='multisig' && s['signatures']>=1){ - h += ' '+s['signatures']; - } - h += ''; - h += ''; - if(s['type']=='multisig'){ - var script = coinjs.script(); - var rs = script.decodeRedeemScript(s.script); - h += rs['signaturesRequired']+' of '+rs['pubkeys'].length; - } else { - h += ''; - } - h += ''; - h += ''; - }); - - $(h).appendTo("#verifyTransactionData .ins tbody"); - - h = ''; - $.each(decode.outs, function(i,o){ - - 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 += ''; - h += ''; - h += ''+(o.value/100000000).toFixed(8)+''; - h += ''; - h += ''; - } else { - - 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 += ''; - h += ''; - h += ''+(o.value/100000000).toFixed(8)+''; - h += ''; - h += ''; - } - }); - $(h).appendTo("#verifyTransactionData .outs tbody"); - - $(".verifyLink").attr('href','?verify='+$("#verifyScript").val()); - return true; - } catch(e) { - return false; - } - } - - 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; - } - - 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"); - $(".verifyLink").attr('href','?verify='+$("#verifyScript").val()); - return true; - } catch (e) { - return false; - } - } else { - return false; - } - } - - function decodeHDaddress(){ - var s = $("#verifyScript").val(); - 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){ - 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; - } - } catch (e) { - return false; - } - } - - 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 += ''; - html += ''+i+''; - html += ''; - html += ''; - html += ''; - html += ''; - html += ''; - } - $(html).appendTo("#verifyHDaddress .derived_data table tbody"); - } - - - /* 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()); - - 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 */ - - 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; - } - - $("#newKeysBtn, #newHDKeysBtn").click(); - - var _getBroadcast = _get("broadcast"); - if(_getBroadcast[0]){ - $("#rawTransaction").val(_getBroadcast[0]); - $("#rawSubmitBtn").click(); - window.location.hash = "#broadcast"; - } - - var _getVerify = _get("verify"); - if(_getVerify[0]){ - $("#verifyScript").val(_getVerify[0]); - $("#verifyBtn").click(); - window.location.hash = "#verify"; - } - - $(".qrcodeBtn").click(function(){ - $("#qrcode").html(""); - var thisbtn = $(this).parent().parent(); - 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(); - if(qrstr.length > 1024){ - $("#qrcode").html("

Sorry the data is too long for the QR generator.

"); - } - } else { - var qrcode = new QRCode("qrcode"); - qrstr = "bitcoin:"+$('.address',thisbtn).val(); - } - - if(qrstr){ - qrcode.makeCode(qrstr); - } - }); - - $('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(); - - /* 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(){ - - // log out of openwallet - $("#walletLogout").click(); - - $("#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(" 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]); - $("#coinjs_priv").val(o[1]); - $("#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(""); - if(host=="blockr.io_litecoin"){ - $("#rawSubmitBtn").click(function(){ - rawSubmitBlockrio_litecoin(this) - }); - } else if(host=="blockr.io_bitcoinmainnet"){ - $("#rawSubmitBtn").click(function(){ - rawSubmitBlockrio_BitcoinMainnet(this); - }); - } else { - $("#rawSubmitBtn").click(function(){ - rawSubmitDefault(this); // revert to default - }); - } - } - - function configureGetUnspentTx(){ - $("#redeemFromBtn").attr('rel',$("#coinjs_utxo option:selected").val()); - } - - /* 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 - tempX = event.clientX + document.body.scrollLeft; - tempY = event.clientY + document.body.scrollTop; - } else { - tempX = e.pageX; - tempY = e.pageY; - }; - - if (tempX < 0){tempX = 0}; - if (tempY < 0){tempY = 0}; - var xEnt = Crypto.util.bytesToHex([tempX]).slice(-2); - var yEnt = Crypto.util.bytesToHex([tempY]).slice(-2); - var addEnt = xEnt.concat(yEnt); - - if ($("#entropybucket").html().indexOf(xEnt) == -1 && $("#entropybucket").html().indexOf(yEnt) == -1) { - $("#entropybucket").html(addEnt + $("#entropybucket").html()); - }; - - if ($("#entropybucket").html().length > 128) { - $("#entropybucket").html($("#entropybucket").html().slice(0, 128)) - }; - - return true; - }; -}); diff --git a/js/cointoolkit.js b/js/cointoolkit.js new file mode 100644 index 00000000..681aa4ae --- /dev/null +++ b/js/cointoolkit.js @@ -0,0 +1,2440 @@ +$(document).ready(function() { + + if(window.location.hostname == "ttutdxh-nubits.github.io" && window.location.protocol != 'https:') { + window.location.href = "https:" + window.location.href.substring(window.location.protocol.length); + } + + var toolkit = {}; + + function updateQueryStringParameter(uri, key, value) { + var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i"); + var separator = uri.indexOf('?') !== -1 ? "&" : "?"; + if (uri.match(re)) { + return uri.replace(re, '$1' + key + "=" + value + '$2'); + } + else { + return uri + separator + key + "=" + value; + } + } + + 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()/("1e"+coinjs.decimalPlaces); + $("#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); + } + + + function scannerStart(){ + 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|nu|Nu|bcexchange|B\&C\ Exchange|ppcoin|peercoin)\:([a-z0-9]{27,34})/i); + var result = match ? match[2] : data; + $(""+$("#qrcode-scanner-callback-to").html()).val(result); + $("#qrScanClose").click(); + } + }); + } else { + $("#videoReaderError").removeClass("hidden"); + $("#videoReader, #videoSource").addClass("hidden"); + } + } + + /* function to determine what we are redeeming from */ + function redeemingFrom(string){ + var r = {}; + var decode = coinjs.addressDecode(string); + if(decode.version == coinjs.pub){ // regular address + r.addr = string; + r.from = 'address'; + r.isMultisig = false; + } else if (decode.version == coinjs.priv){ // wif key + var a = coinjs.wif2address(string); + r.addr = a['address']; + r.from = 'wif'; + r.isMultisig = false; + } else if (decode.version == coinjs.multisig){ // mulisig address + r.addr = ''; + r.from = 'multisigAddress'; + r.isMultisig = false; + } else { + var script = coinjs.script(); + var decodeRs = script.decodeRedeemScript(string); + if(decodeRs){ // redeem script + r.addr = decodeRs['address']; + r.from = 'redeemScript'; + r.decodedRs = decodeRs; + r.isMultisig = true; + } else { // something else + r.addr = ''; + r.from = 'other'; + r.isMultisig = false; + } + } + return r; + } + + /* global function to add outputs to page */ + function addOutput(tx, n, script, amount) { + if(tx){ + if($("#inputs .txId:last").val()!=""){ + $("#inputs .txidAdd:last").click(); + } + + $("#inputs .row:last input").attr('disabled',true); + + $("#inputs .txId:last").val(tx); + $("#inputs .txIdN:last").val(n); + $("#inputs .txIdAmount:last").val(amount); + $("#inputs .txIdScript:last").val(script); + } + } + + /* math to calculate the inputs and outputs */ + + 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(coinjs.decimalPlaces)); + } + }); + 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(coinjs.decimalPlaces)); + } + totalFee(); + }).keyup(); + } + + function totalFee(){ + var fee = (($("#totalInput").html()*1) - ($("#totalOutput").html()*1)).toFixed(coinjs.decimalPlaces); + $("#transactionFee").val((fee>0)?fee:'0.00'); + } + + function decodeRedeemScript(){ + var script = coinjs.script(); + var decode = script.decodeRedeemScript($("#verifyScript").val()); + if(decode){ + $("#verifyRsData .multisigAddress").val(decode['address']); + $("#verifyRsData .multisigScriptHash").val(decode['scriptHash']); + $("#verifyRsData .multisigScriptHashKnown").val((known.scriptHash[decode['scriptHash']])?known.scriptHash[decode['scriptHash']].name:''); + $("#verifyRsData .signaturesRequired").html(decode['signaturesRequired']); + $("#verifyRsData table tbody").html(""); + for(var i=0;i').appendTo("#verifyRsData table tbody"); + } + $("#verifyRsData").removeClass("hidden"); + $("#verify .verifyLink").val(document.location.origin+''+document.location.pathname+'?mode='+$("#coinSelector").val()+'&verify='+$("#verifyScript").val()); + return true; + } else { + return false; + } + } + + function decodeTransactionScript(){ + var tx = coinjs.transaction(); + try { + var decode = tx.deserialize($("#verifyScript").val()); + $("#verifyTransactionData .transactionVersion").html(decode['version']); + $("#verifyTransactionData .transactionTime").html(new Date(decode['nTime']*1000).toUTCString()); + $("#verifyTransactionData .transactionSize").html(decode.size()+' bytes'); + $("#verifyTransactionData .transactionLockTime").html((decode['lock_time'] >= 500000000)?new Date(decode['nTime']*1000).toUTCString():"Block height "+decode['lock_time']); + $("#verifyTransactionData .transactionUnit").html(String.fromCharCode(decode['nUnit'])); + $("#verifyTransactionData .verifyToSign").on( "click", function() { + $("#signTransaction").val(decode.serialize()).fadeOut().fadeIn(); + window.location.hash = "#sign"; + }); + $("#verifyTransactionData .verifyToBroadcast").on( "click", function() { + $("#broadcast #rawTransaction").val(decode.serialize()).fadeOut().fadeIn(); + window.location.hash = "#broadcast"; + }); + $("#verifyTransactionData").removeClass("hidden"); + $("#verifyTransactionData tbody").html(""); + + $("#verifyTransactionData .ins tbody").html(""); + $("#verifyTransactionData .fee").addClass("hidden").attr("style", ""); + + var inAmountAvailable = 0; + var amountTotal = 0; + + var h = ''; + $.each(decode.ins, function(i,o){ + var s = decode.extractScriptKey(i); + h = ''; + h += ''; + h += ''+o.outpoint.index+''; + h += ''; + h += 'Advanced'; + //h += 'Advanced'; + h += ''; + h += ''; + if(s['type']=='multisig' && s['signatures']>=1){ + h += ''; + h += ' '+s['signatures']; + h += ''; + } + h += ''; + h += ''; + if(s['type']=='multisig'){ + h += ''; + var script = coinjs.script(); + var rs = script.decodeRedeemScript(s.script); + h += rs['signaturesRequired']+' of '+rs['pubkeys'].length; + h += ''; + } else { + h += ''; + } + h += ''; + h += ''; + + $(h).appendTo("#verifyTransactionData .ins tbody"); + + $("#verifyTransactionData .ins tbody").data("tx", decode); + + if (toolkit.getInputAmount != "disabled") { + (function (inputid, total) { + providers[$("#coinSelector").val()].getInputAmount[toolkit.getInputAmount](o.outpoint.hash, o.outpoint.index, function(result) { + $("#verifyTransactionData .ins tbody td[data-inputid="+inputid+"]").html((result)?coinjs.formatAmount(result):'Not found'); + if (result) { + amountTotal += result; + if (++inAmountAvailable == total) { + $.each(decode.outs, function(i,o){ + amountTotal -= o.value; + }); + + if ((amountTotal/("1e"+coinjs.decimalPlaces)).toFixed(coinjs.decimalPlaces) > 0.011) { + $("#verifyTransactionData .fee").attr("style", "color: red;") + } + $("#verifyTransactionData .fee").removeClass("hidden"); + $("#verifyTransactionData .fee .amount").html(coinjs.formatAmount(amountTotal)); + } + } + }); + })(i, decode.ins.length); + } else { + $("#verifyTransactionData .ins tbody td[data-inputid="+i+"]").html("Not available"); + } + }); + + h = ''; + $.each(decode.outs, function(i,o){ + + 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 += ''; + h += ''; + h += ''; // to account for known address value + h += ''+(o.value/("1e"+coinjs.decimalPlaces)).toFixed(coinjs.decimalPlaces)+''; + h += ''; + h += ''; + } else { + + var addr = ''; + var identity = ''; + if(o.script.chunks.length==5){ + var pubKeyHash = Crypto.util.bytesToHex(o.script.chunks[2]) + addr = coinjs.scripthash2address(pubKeyHash, coinjs.pub); + $.each(known.pubKey, function(pubkey, id) { + if (coinjs.pubkey2address(pubkey, coinjs.pub) == addr) { + identity = known.pubKey[pubkey].name; + return false; + } + }); + } else { + var scriptHash = Crypto.util.bytesToHex(o.script.chunks[1]); + addr = coinjs.scripthash2address(scriptHash, coinjs.multisig); + if (known.scriptHash[scriptHash]) { + identity = known.scriptHash[scriptHash].name; + } + } + + + + + h += ''; + h += ''; + h += ''; + h += ''+coinjs.formatAmount(o.value)+''; + h += 'Advanced'; + //h += 'Advanced'; + h += ''; + } + }); + $(h).appendTo("#verifyTransactionData .outs tbody"); + + $("#verify .verifyLink").val(document.location.origin+''+document.location.pathname+'?mode='+$("#coinSelector").val()+'&verify='+$("#verifyScript").val()); + return true; + } catch(e) { + return false; + } + } + + function decodeMultiSig(tx, i) { + var html = ''; + var list = tx.listMultiSignature(i); + + for (var pubkey in list) { + identity = ""; + if (known.pubKey[pubkey]) { + identity = known.pubKey[pubkey].name; + } + + var address = coinjs.pubkey2address(pubkey); + var signature_position = ''; + if (list[pubkey]) { + for (var x = 0; x < list[pubkey].length; x++) { + if (x > 0) {signature_position += ", "} + signature_position += ''+(list[pubkey][x].pos+1)+'' + } + } + html += '\ + \ + '+signature_position+'\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + '; + } + + $("#modalMultisig table tbody").html(html); + $("#modalMultisig .combine .alert").addClass("hidden"); + + $("#modalMultisig .combineTx").click(function() { + var newTx = tx.combineMultiSignature($("#modalMultisig .combine textarea").val()); + if (newTx) { + if (coinjs.debug) {console.log(newTx, newTx.serialize())}; + $("#verifyScript").val(newTx.serialize()).fadeOut().fadeIn(); + $("#verifyBtn").click(); + + $("#modalMultisig .combine .alert").addClass("hidden"); + $("#modalMultisig").modal("hide"); + + window.location.hash = "#verify"; + } else { + $("#modalMultisig .combine .alert").removeClass("hidden"); + } + }); + $("#modalMultisig").modal("show"); + } + + function decodeScript(script) { + var asm = ''; + var multisig = false; + + var pieces = script.toASM().split(" "); + for (i = 0; i < pieces.length; i++) { + if (i == pieces.length-1) { + var maybemultisig = coinjs.script(pieces[i]); + if (maybemultisig.chunks[maybemultisig.chunks.length - 1] == coinjs.opcode.OP_CHECKMULTISIG) { + multisig = true; + } + } + + asm += ''; + + + if (multisig) { + asm += ''+pieces[i]+'' + + var inner_pieces = maybemultisig.toASM().split(" "); + for (x = 0; x < inner_pieces.length; x++) { + asm += ''+inner_pieces[x]; + console.log(known.scriptHash[inner_pieces[x]]); + if (known.pubKey[inner_pieces[x]]) { + asm += ' (Match with '+known.pubKey[inner_pieces[x]].name+')'; + } else if (known.scriptHash[inner_pieces[x]]) { + asm += ' (Match with '+known.scriptHash[inner_pieces[x]].name+')'; + } + asm += '
'; + } + } else { + asm += pieces[i]; + if (known.pubKey[pieces[i]]) { + asm += ' (Match with '+known.pubKey[pieces[i]].name+')'; + } else if (known.scriptHash[pieces[i]]) { + asm += ' (Match with '+known.scriptHash[pieces[i]].name+')'; + } + } + + asm += '

'; + } + + $("#modalScript .asm").html(asm); + + $("#modalScript").modal("show"); + } + + 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; + } + + 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"); + $("#verify .verifyLink").val(document.location.origin+''+document.location.pathname+'?mode='+$("#coinSelector").val()+'&verify='+$("#verifyScript").val()); + return true; + } catch (e) { + return false; + } + } else { + return false; + } + } + + function decodeHDaddress(){ + var s = $("#verifyScript").val(); + 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){ + 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 .hdpub").val(hd.keys_extended.pubkey); + $("#verifyHDaddress .hdaddress").val(hd.keys.address); + $("#verifyHDaddress .hdpubkey").val(hd.keys.pubkey); + $("#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(); + // Not sharing private keys! $("#verify .verifyLink").val(document.location.origin+''+document.location.pathname+'?mode='+$("#coinSelector").val()+'&verify='+$("#verifyScript").val()); + $("#verifyHDaddress").removeClass("hidden"); + return true; + } + } catch (e) { + return false; + } + } + + 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 += ''; + html += ''+i+''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + } + $(html).appendTo("#verifyHDaddress .derived_data table tbody"); + } + + function getMouseXY(e) { + var tempX = 0; + var tempY = 0; + if (IE) { // If browser is IE + tempX = event.clientX + document.body.scrollLeft; + tempY = event.clientY + document.body.scrollTop; + } else { + tempX = e.pageX; + tempY = e.pageY; + }; + + if (tempX < 0){tempX = 0}; + if (tempY < 0){tempY = 0}; + var xEnt = Crypto.util.bytesToHex([tempX]).slice(-2); + var yEnt = Crypto.util.bytesToHex([tempY]).slice(-2); + var addEnt = xEnt.concat(yEnt); + + if ($("#entropybucket").html().indexOf(xEnt) == -1 && $("#entropybucket").html().indexOf(yEnt) == -1) { + $("#entropybucket").html(addEnt + $("#entropybucket").html()); + }; + + if ($("#entropybucket").html().length > 128) { + $("#entropybucket").html($("#entropybucket").html().slice(0, 128)) + }; + + return true; + }; + + 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; + } + + /* external providers */ + + var nuBasedExplorer = { + listUnspent: function(endpoint) { + return function(redeem){ + var msgSucess = ' Retrieved unspent inputs from address '+redeem.addr+'' + var msgError = ' Unexpected error, unable to retrieve unspent outputs! Is ' + endpoint + '/ down?'; + $.ajax ({ + type: "GET", + url: 'https://crossorigin.me/' + endpoint + '/api/v1/addressUnspent/' + redeem.addr, + dataType: "json", + error: function(data) { + $("#redeemFromStatus").removeClass('hidden').html(msgError); + $("#redeemFromBtn").html("Load").attr('disabled',false); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if (data.length == 0) { + $("#redeemFromStatus").removeClass('hidden').html(msgError); + $("#redeemFromBtn").html("Load").attr('disabled',false); + } else { + for(var i=0;i').attr('disabled',true); + $.ajax ({ + type: "POST", + url: endpoint + "/api/v1/sendrawtx", + data: { + "rawTx": $("#rawTransaction").val(), + "checkInputs": 1 + }, + dataType: "json", + error: function(data) { + data = $.parseJSON(data.responseText); + var r = ''; + r += (data.data) ? data.data : ''; + r += (data.status) ? ' '+data.status : ''; + r = (r!='') ? r : ' Failed to broadcast. Internal server error'; + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend(''); + }, + success: function(data) { + data = $.parseJSON(data.responseText); + if(data.success==true){ + $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.data); + } else { + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Error'+data.status).prepend(''); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + } + } + }; + + var bcBasedExplorer = { + listUnspent: function(endpoint) { + return function(redeem){ + var msgSucess = ' Retrieved unspent inputs from address '+redeem.addr+'' + var msgError = ' Unexpected error, unable to retrieve unspent outputs! Is ' + endpoint + '/ down?'; + var msgError = ' According to ' + endpoint + '/ unspent balance for '+redeem.addr+' is 0'; + $.ajax ({ + type: "GET", + url: endpoint + '/api/v1/unspent/' + redeem.addr, + dataType: "json", + error: function(data) { + $("#redeemFromStatus").removeClass('hidden').html(msgError); + $("#redeemFromBtn").html("Load").attr('disabled',false); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if (data.txs.length == 0) { + $("#redeemFromStatus").removeClass('hidden').html(msgError); + $("#redeemFromBtn").html("Load").attr('disabled',false); + } else { + for(var i=0;i').attr('disabled',true); + $.ajax ({ + type: "POST", + url: endpoint + "/api/v1/sendrawtx", + data: { + "rawTx": $("#rawTransaction").val(), + "checkInputs": 1 + }, + dataType: "json", + error: function(data) { + data = $.parseJSON(data.responseText); + var r = ''; + r += (data.data) ? data.data : ''; + r += (data.status) ? ' '+data.status : ''; + r = (r!='') ? r : ' Failed to broadcast. Internal server error'; + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend(''); + }, + success: function(data) { + data = $.parseJSON(data.responseText); + if(data.success==true){ + $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.data); + } else { + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Error'+data.status).prepend(''); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + } + } + }; + + var gitmultisig_listunspent = function(redeem, github_repository) { + if (!redeem.isMultisig) { + $("#redeemFromStatus").removeClass('hidden').html('This provider does not store scripts of unspent transactions, so transactions from single-signature addresses are impossible to create. Please select another provider'); + $("#redeemFromBtn").html("Load").attr('disabled',false); + return; + } + + var msgSucess = ' Retrieved unspent inputs from address '+redeem.addr+'' + var msgError = ' Unexpected error, unable to retrieve unspent outputs! This provider only store unspent outputs for FLOT addresses https://github.com/'+github_repository+'. Please select another provider'; + $.ajax ({ + type: "GET", + url: "https://raw.githubusercontent.com/"+github_repository+"/master/"+redeem.addr+"/unspent", + dataType: "json", + error: function(data) { + $("#redeemFromStatus").removeClass('hidden').html(msgError); + $("#redeemFromBtn").html("Load").attr('disabled',false); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if (typeof(data.unspent) != "object") { + $("#redeemFromStatus").removeClass('hidden').html(msgError); + $("#redeemFromBtn").html("Load").attr('disabled',false); + } else { + console.log(1); + for(var i=0;i Unexpected error, unable to retrieve unspent outputs!'); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if (data.status && data.data && data.status=='success'){ + $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); + for(var i in data.data.unspent){ + var o = data.data.unspent[i]; + var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.script; + + addOutput(o.tx, o.n, script, o.amount); + } + } else { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); + } + }, + complete: function(data, status) { + $("#redeemFromBtn").html("Load").attr('disabled',false); + totalInputAmount(); + } + }); + }, + "coinb.in": function(redeem){ + $.ajax ({ + type: "GET", + url: coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=unspent&address='+redeem.addr+'&r='+Math.random(), + dataType: "xml", + error: function(data) { + if (coinjs.debug) {console.log(data)}; + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs!'); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if ($(data).children("request").children("result").text()){ + $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); + $.each($(data).children("request").children("unspent").children(), function(i,o){ + var tx = (($(o).find("tx_hash").text()).match(/.{1,2}/g).reverse()).join("")+''; + var n = $(o).find("tx_output_n").text(); + var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : $(o).find("script").text(); + var amount = (($(o).find("value").text()*1)/("1e"+coinjs.decimalPlaces)).toFixed(coinjs.decimalPlaces); + + addOutput(tx, n, script, amount); + }); + } else { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); + } + }, + complete: function(data, status) { + $("#redeemFromBtn").html("Load").attr('disabled',false); + totalInputAmount(); + } + }); + } + }, + broadcast: { + "blockr.io": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('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 r = ''; + r += (data.data) ? data.data : ''; + r += (data.message) ? ' '+data.message : ''; + r = (r!='') ? r : ' Failed to broadcast. Internal server error'; + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend(''); + }, + success: function(data) { + if((data.status && data.data) && data.status=='success'){ + $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.data); + } else { + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend(''); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + }, + "coinb.in": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('Please wait, loading... ').attr('disabled',true); + $.ajax ({ + type: "G", + 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(''); + }, + 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(' '); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + } + }, + getInputAmount: { + "blockr.io": function(txid, index, callback) { + $.ajax ({ + type: "GET", + url: "https://btc.blockr.io/api/v1/tx/info/"+txid, + dataType: "json", + error: function(data) { + callback(false); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if (data.status && data.data && data.status=='success' && data.data.vouts[index]){ + callback(parseInt(data.data.vouts[index].amount*("1e"+coinjs.decimalPlaces), 10)); + } else { + callback(false); + } + } + }); + } + } + }, + bitcoin_cash: { + listUnspent: { + "bcash": function(redeem){ + $.ajax ({ + type: "GET", + url: "https://api.blocktrail.com/v1/BCC/address/"+redeem.addr+"/unspent-outputs?api_key=MY_APIKEY", + dataType: "json", + error: function(data) { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs!'); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if(data){ + $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); + for(var i in data.data){ + var o = data.data[i]; + var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.script_hex; + + addOutput(o.hash, o.index, script, o.value / ("1e"+coinjs.decimalPlaces)); + } + } else { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); + } + }, + complete: function(data, status) { + $("#redeemFromBtn").html("Load").attr('disabled',false); + totalInputAmount(); + } + }); + }, + "coinb.in": function(redeem){ + $.ajax ({ + type: "GET", + url: coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=addresses&request=unspent&address='+redeem.addr+'&r='+Math.random(), + dataType: "xml", + error: function(data) { + if (coinjs.debug) {console.log(data)}; + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs!'); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if ($(data).children("request").children("result").text()){ + $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); + $.each($(data).children("request").children("unspent").children(), function(i,o){ + var tx = (($(o).find("tx_hash").text()).match(/.{1,2}/g).reverse()).join("")+''; + var n = $(o).find("tx_output_n").text(); + var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : $(o).find("script").text(); + var amount = (($(o).find("value").text()*1)/("1e"+coinjs.decimalPlaces)).toFixed(coinjs.decimalPlaces); + + addOutput(tx, n, script, amount); + }); + } else { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); + } + }, + complete: function(data, status) { + $("#redeemFromBtn").html("Load").attr('disabled',false); + totalInputAmount(); + } + }); + } + }, + broadcast: { + "blockr.io": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('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 r = ''; + r += (data.data) ? data.data : ''; + r += (data.message) ? ' '+data.message : ''; + r = (r!='') ? r : ' Failed to broadcast. Internal server error'; + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend(''); + }, + success: function(data) { + if((data.status && data.data) && data.status=='success'){ + $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.data); + } else { + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend(''); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + }, + "coinb.in": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('Please wait, loading... ').attr('disabled',true); + $.ajax ({ + type: "G", + 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(''); + }, + 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(' '); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + } + }, + }, + litecoin: { + listUnspent: { + "chain.so": function(redeem){ + $.ajax ({ + type: "GET", + url: "https://chain.so/api/v2/get_tx_unspent/ltc/"+redeem.addr, + dataType: "json", + error: function(data) { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs!'); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if((data.status && data.data) && data.status=='success'){ + $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); + for(var i in data.data.txs){ + var o = data.data.txs[i]; + var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.script_hex; + + addOutput(o.txid, o.output_no, script, o.value); + } + } else { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); + } + }, + complete: function(data, status) { + $("#redeemFromBtn").html("Load").attr('disabled',false); + totalInputAmount(); + } + }); + } + }, + broadcast: { + "blockcypher": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('Please wait, loading... ').attr('disabled',true); + $.ajax ({ + type: "POST", + url: "https://api.blockcypher.com/v1/ltc/main/txs/push", + data: JSON.stringify({"tx":$("#rawTransaction").val()}), + dataType: "json", + error: function(data) { + var r = ''; + r += (data.data) ? data.data : ''; + r += (data.message) ? ' '+data.message : ''; + r = (r!='') ? r : ' Failed to broadcast. Internal server error'; + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend(''); + }, + success: function(data) { + if(data.tx.hash){ + $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.tx.hash); + } else { + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend(''); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).hmtl(orig_html).attr('disabled',false); + } + }); + } + } + }, + Dogecoin: { + listUnspent: { + "chain.so": function(redeem){ + $.ajax ({ + type: "GET", + url: "https://chain.so/api/v2/get_tx_unspent/DOGE/"+redeem.addr, + dataType: "json", + error: function(data) { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs!'); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if((data.status && data.data) && data.status=='success'){ + $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); + for(var i in data.data.txs){ + var o = data.data.txs[i]; + var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.script_hex; + + addOutput(o.txid, o.output_no, script, o.value); + } + } else { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); + } + }, + complete: function(data, status) { + $("#redeemFromBtn").html("Load").attr('disabled',false); + totalInputAmount(); + } + }); + } + }, + broadcast: { + "blockcypher": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('Please wait, loading... ').attr('disabled',true); + $.ajax ({ + type: "POST", + url: "https://api.blockcypher.com/v1/doge/main/txs/push", + data: JSON.stringify({"tx":$("#rawTransaction").val()}), + dataType: "json", + error: function(data) { + var r = ''; + r += (data.data) ? data.data : ''; + r += (data.message) ? ' '+data.message : ''; + r = (r!='') ? r : ' Failed to broadcast. Internal server error'; + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend(''); + }, + success: function(data) { + if(data.tx.hash){ + $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.tx.hash); + } else { + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend(''); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + }, + "coinb.in": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('Please wait, loading... ').attr('disabled',true); + $.ajax ({ + type: "G", + 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(''); + }, + 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(' '); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + } + }, + getInputAmount: { + "blockcypher": function(txid, index, callback) { + $.ajax ({ + type: "GET", + url: "https://api.blockcypher.com/v1/doge/main/txs/"+txid, + dataType: "json", + error: function(data) { + callback(false); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if (data.outputs[index]){ + callback(data.outputs[index].value); //callback(parseInt(data.outputs[index].value*("1e"+coinjs.decimalPlaces), 10)); + } else { + callback(false); + } + } + }); + } + } + }, + DASH: { + listUnspent: { + "insight.dash": function(redeem){ + $.ajax ({ + type: "GET", + url: "https://insight.dash.siampm.com/api/addr/"+redeem.addr+"/utxo", + dataType: "json", + error: function(data) { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs!'); + }, + success: function(data) { + if (coinjs.debug) {console.log(data)}; + if(data){ + $("#redeemFromAddress").removeClass('hidden').html(' Retrieved unspent inputs from address '+redeem.addr+''); + for(var i in data){ + var o = data[i]; + var script = (redeem.isMultisig==true) ? $("#redeemFrom").val() : o.scriptPubKey; + + addOutput(o.txid, o.vout, script, o.amount); + } + } else { + $("#redeemFromStatus").removeClass('hidden').html(' Unexpected error, unable to retrieve unspent outputs.'); + } + }, + complete: function(data, status) { + $("#redeemFromBtn").html("Load").attr('disabled',false); + totalInputAmount(); + } + }); + } + }, + broadcast: { + "insight.dash": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('Please wait, loading... ').attr('disabled',true); + $.ajax ({ + type: "POST", + url: "https://insight.dash.siampm.com/api/tx/send", + data: {'rawtx':$("#rawTransaction").val()}, + dataType: "json", + error: function(data) { + var r = ''; + r += (data.data) ? data.data : ''; + r += (data.message) ? ' '+data.message : ''; + r = (r!='') ? r : ' Failed to broadcast. Internal server error'; + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend(''); + }, + success: function(data) { + if((data.status && data.data) && data.status=='success'){ + $("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' Txid: '+data.data); + } else { + $("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend(''); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + }, + "coinb.in": function(thisbtn){ + var orig_html = $(thisbtn).html(); + $(thisbtn).html('Please wait, loading... ').attr('disabled',true); + $.ajax ({ + type: "G", + 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(''); + }, + 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(' '); + } + }, + complete: function(data, status) { + $("#rawTransactionStatus").fadeOut().fadeIn(); + $(thisbtn).html(orig_html).attr('disabled',false); + } + }); + } + } + }, + nubits: { + listUnspent: { + "blockexplorer.nu": nuBasedExplorer.listUnspent('https://blockexplorer.nu'), + "FLOT @dysconnect git-multisig repository": function(redeem) { + gitmultisig_listunspent(redeem, "dc-tcs/flot-operations"); + }, + "FLOT @masterOfDisaster git-multisig repository": function(redeem) { + gitmultisig_listunspent(redeem, "Lamz0rNewb/flot-operations"); + }, + "FLOT @jooize git-multisig repository": function(redeem) { + gitmultisig_listunspent(redeem, "jooize/flot-operations"); + }, + }, + broadcast: { + "blockexplorer.nu": nuBasedExplorer.broadcast('https://blockexplorer.nu') + }, + getInputAmount: { + "blockexplorer.nu": nuBasedExplorer.getInputAmount('https://blockexplorer.nu') + } + }, + nushares: { + listUnspent: { + "blockexplorer.nu": nuBasedExplorer.listUnspent('https://blockexplorer.nu') + }, + broadcast: { + "blockexplorer.nu": nuBasedExplorer.broadcast('https://blockexplorer.nu') + }, + getInputAmount: { + "blockexplorer.nu": nuBasedExplorer.getInputAmount('https://blockexplorer.nu') + } + }, + blockcredits: { + listUnspent: { + "bcblockexplorer.com": nuBasedExplorer.listUnspent('https://bcblockexplorer.com') + }, + broadcast: { + "bcblockexplorer.com": nuBasedExplorer.broadcast('https://bcblockexplorer.com') + }, + getInputAmount: { + "bcblockexplorer.com": nuBasedExplorer.getInputAmount('https://bcblockexplorer.com') + } + }, + blockshares: { + listUnspent: { + "bcblockexplorer.com": nuBasedExplorer.listUnspent('https://bcblockexplorer.com') + }, + broadcast: { + "bcblockexplorer.com": nuBasedExplorer.broadcast('https://bcblockexplorer.com') + }, + getInputAmount: { + "bcblockexplorer.com": nuBasedExplorer.getInputAmount('https://bcblockexplorer.com') + } + } + } + + /* page load code */ + + /* 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'; + s += (s+''+s); + + for(i=0;i<=50;i++){ + s = Crypto.SHA256(s); + } + + coinjs.compressed = true; + var keys = coinjs.newKeys(s); + + $("#walletAddress").html(keys.address); + $("#walletHistory").attr('href','//btc.blockr.io/address/info/'+keys.address); + + $("#walletQrCode").html(""); + var qrcode = new QRCode("walletQrCode"); + qrcode.makeCode(keys.address); + + $("#walletKeys .privkey").val(keys.wif); + $("#walletKeys .pubkey").val(keys.pubkey); + $("#walletKeys .privkeyaes").val(CryptoJS.AES.encrypt(keys.wif, pass)); + + $("#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(' '); + }); + + $("#walletLogout").click(function(){ + $("#openEmail").val(""); + $("#openPass").val(""); + $("#openPassConfirm").val(""); + + $("#openLogin").show(); + $("#openWallet").addClass("hidden").show(); + + $("#walletAddress").html(""); + $("#walletHistory").attr('href','//btc.blockr.io/address/info/'); + + $("#walletQrCode").html(""); + var qrcode = new QRCode("walletQrCode"); + qrcode.makeCode(""); + + $("#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; // TODO: generate address from dev known pubkey + 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); + total += amount.val()*1; + tx.addoutput(addr.val(), amount.val()*1); + }); + + thisbtn.attr('disabled',true); + + tx.addUnspent($("#walletAddress").html(), function(data){ + var dvalue = data.value/("1e"+coinjs.decimalPlaces); + if(dvalue>=total){ + var change = dvalue-total; + if(change>0){ + 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){ // TODO: function no longer part of coin.js + + + + r.broadcast = function(callback, txhex){ + var tx = txhex || this.serialize(); + coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=bitcoin&request=sendrawtransaction&rawtx='+tx+'&r='+Math.random(), callback, "GET"); + } + + + 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,' ')); + thisbtn.attr('disabled',false); + } + + // 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(); + thisbtn.attr('disabled',false); + } + + $("#walletLoader").addClass("hidden"); + }); + }); + + $("#walletSendBtn").click(function(){ + + $("#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(coinjs.decimalPlaces); + + 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(' One or more input has an error'); + } + }); + + $("#walletShowSpend").click(function(){ + $("#walletSpend").removeClass("hidden"); + $("#walletKeys").removeClass("hidden").addClass("hidden"); + }); + + $("#walletSpendTo .addressAdd").click(function(){ + var clone = '
'+$(this).parent().html()+'
'; + $("#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(); + }); + }); + + /* 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, ($("#newBrainwallet").is(":checked") && $("#brainwalletIsPrivKey").is(":checked"))); + $("#newGeneratedAddress").val(coin.address); + $("#newPubKey").val(coin.pubkey); + $("#newPrivKeyWif").val(coin.wif); + $("#newPrivKey").val(coin.privkey); + + /* encrypted key code */ + if((!$("#encryptKey").is(":checked")) || $("#aes256pass").val()==$("#aes256pass_confirm").val()){ + $("#aes256passStatus").addClass("hidden"); + if($("#encryptKey").is(":checked")){ + $("#aes256wifkey").removeClass("hidden"); + } + } else { + $("#aes256passStatus").removeClass("hidden"); + } + $("#newPrivKeyEnc").val(CryptoJS.AES.encrypt(coin.wif, $("#aes256pass").val())+''); + }); + + $("#newBrainwallet").click(function(){ + if($(this).is(":checked")){ + $("#keyFromData").removeClass("hidden"); + } else { + $("#keyFromData").addClass("hidden"); + } + }); + + $("#encryptKey").click(function(){ + if($(this).is(":checked")){ + $("#aes256passform").removeClass("hidden"); + } else { + $("#aes256wifkey, #aes256passform, #aes256passStatus").addClass("hidden"); + } + }); + + /* 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(' 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']); + $("#multiSigData .scriptUrl").val(document.location.origin+''+document.location.pathname+'?mode='+$("#coinSelector").val()+'&verify='+multisig['redeemScript']+'#verify'); + $("#multiSigData").removeClass('hidden').addClass('show').fadeIn(); + $("#releaseCoins").removeClass('has-error'); + } else { + $("#multiSigErrorMsg").html(' One or more public key is invalid!').fadeIn(); + } + }); + + $("#newMultiSigAddressSort").click(function(){ + var mylist = $("#multisigPubKeys .sort"); + var listitems = mylist.children(); + listitems.sort(function(a, b) { + var compA = $(a).find('.pubkey').val().toUpperCase(); + var compB = $(b).find('.pubkey').val().toUpperCase(); + return (compA < compB) ? -1 : (compA > compB) ? 1 : 0; + }) + $.each(listitems, function(idx, itm) { + console.log(itm); + mylist.append(itm); + }); + $("#multiSigData").addClass("hidden"); + }); + + $("#multisigPubKeys .list").on('input change', '.pubkey', function() { + var val = (known.pubKey[$(this).val()])?known.pubKey[$(this).val()].name:''; + $(this).parent().parent().find('.id').val(val) + }); + + $("#multisigPubKeys .list") + .on('click', '.pubkeyAdd', function(){ + if($("#multisigPubKeys .list .pubkeyRemove").length<14){ + var clone = $(this).parent().parent().clone(); + $(this).parent().parent().after(clone); + $(clone).find('.pubkey').val('').change(); + } + $("#multiSigData").addClass("hidden"); + }) + .on('click', '.pubkeyRemove', function(){ + $(this).parent().parent().remove(); + $("#multiSigData").addClass("hidden"); + }); + + $("#mediatorList").change(function(){ + var data = ($(this).val()).split(";"); + $("#mediatorPubkey").val(data[0]); + $("#mediatorEmail").val(data[1]); + $("#mediatorFee").val(data[2]); + }) + + $("#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()).change().fadeOut().fadeIn(); + $("#mediatorClose").click(); + return false; + } else if(count==len){ + $("#multisigPubKeys .pubkeyAdd").click(); + $("#mediatorAddKey").click(); + return false; + } + count++; + }); + + $("#mediatorClose").click(); + } + }); + + /* 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"); + } + }); + + /* new -> transaction code */ + + $("#recipients").on('input change', '.address', function() { + var addr = $(this).val(); + var identity = ''; + var details = coinjs.addressDecode(addr); + if (details.type == 'standard') { + $.each(known.pubKey, function(pubkey, id) { + if (coinjs.pubkey2address(pubkey, coinjs.pub) == addr) { + identity = known.pubKey[pubkey].name; + return false; + } + }); + } else if (details.type == 'multisig') { + $.each(known.scriptHash, function(scripthash, id) { + if (coinjs.scripthash2address(scripthash, coinjs.multisig) == addr) { + identity = known.scriptHash[scripthash].name; + return false; + } + }); + } + + $(this).parent().parent().find('.id').val(identity); + }); + + $("#recipients .addressAddTo").click(function(){ + if($("#recipients .addressRemoveTo").length<100){ + var clone = '

'+$(this).parent().parent().html()+'
'; + $("#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").on('click', '.txidAdd', function(){ + var clone = $(this).parent().parent().clone(); + $("input", clone).attr('disabled', false).val(""); + $(this).parent().parent().after(clone); + }); + + $("#inputs").on('click', '.txidRemove', function(){ + if ($("#inputs .txidRemove").length < 2) return; + $(this).parent().parent().fadeOut().remove(); + totalInputAmount(); + }); + + $("#inputs").on('input change', ".txIdAmount", function(){ + totalInputAmount(); + }).keyup(function(){ + totalInputAmount(); + }); + + $("#transactionBtn").click(function(){ + var tx = coinjs.transaction(); + + $("#transactionCreate, #transactionCreateStatus").addClass("hidden"); + + if(($("#nLockTime").val()).match(/^[0-9]+$/g)){ + tx.lock_time = $("#nLockTime").val()*1; + } + + if(($("#nTime").val()).match(/^[0-9]+$/g)){ + tx.nTime = $("#nTime").val()*1; + } + + $("#inputs .row").removeClass('has-error'); + + $('#putTabs a[href="#txinputs"], #putTabs a[href="#txoutputs"]').attr('style',''); + + $.each($("#inputs .row"), function(i,o){ + if(!($(".txId",o).val()).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")){ + tx.addinput($(".txId",o).val(), $(".txIdN",o).val(), $(".txIdScript",o).val()); + } else { + $('#putTabs a[href="#txinputs"]').attr('style','color:#a94442;'); + } + }); + + $("#recipients .row").removeClass('has-error'); + + $.each($("#recipients .row"), function(i,o){ + var a = ($(".address",o).val()); + var ad = coinjs.addressDecode(a); + if(((a!="") && (ad.version == coinjs.pub || ad.version == coinjs.multisig)) && $(".amount",o).val()!=""){ // address + tx.addoutput(a, $(".amount",o).val()); + } else if (((a!="") && ad.version === 42) && $(".amount",o).val()!=""){ // stealth address + tx.addstealth(ad, $(".amount",o).val()); + } else if (((($("#opReturn").is(":checked")) && a.match(/^[a-f0-9]+$/ig)) && a.length<160) && (a.length%2)==0) { // data + tx.adddata(a); + } else { // neither address nor data + $(o).addClass('has-error'); + $('#putTabs a[href="#txoutputs"]').attr('style','color:#a94442;'); + } + }); + + + if(!$("#recipients .row, #inputs .row").hasClass('has-error')){ + $("#transactionCreate textarea").val(tx.serialize()); + $("#transactionCreate .txSize").html(tx.size()); + + $("#transactionCreate .transactionToSign").on( "click", function() { + $("#signTransaction").val(tx.serialize()).fadeOut().fadeIn();; + window.location.hash = "#sign"; + }); + + $("#transactionCreate").removeClass("hidden"); + + if($("#transactionFee").val()>=0.011){ + $("#modalWarningFeeAmount").html($("#transactionFee").val()); + $("#modalWarningFee").modal("show"); + } + } else { + $("#transactionCreateStatus").removeClass("hidden").html("One or more input or output is invalid").fadeOut().fadeIn(); + } + }); + + $("#inputs .txIdAmount").unbind("").change(function(){ + totalInputAmount(); + }).keyup(function(){ + totalInputAmount(); + }); + + /* code for the qr code scanner */ + + $(".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"); + } + } + }); + + $("#videoSource").unbind("change").change(function(){ + scannerStart() + }); + + } else { + $("#videoSource").addClass("hidden"); + } + scannerStart(); + $("#qrcode-scanner-callback-to").html($(this).attr('forward-result')); + }); + + /* code for the script decoder */ + + $(".scriptDecoder").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"); + } + } + }); + + $("#videoSource").unbind("change").change(function(){ + scannerStart() + }); + + } else { + $("#videoSource").addClass("hidden"); + } + scannerStart(); + $("#qrcode-scanner-callback-to").html($(this).attr('forward-result')); + }); + + /* broadcast code */ + $("#rawSubmitBtn").click(function(){ + var host = $(this).attr('rel'); + providers[$("#coinSelector").val()].broadcast[host](this); + }); + + /* redeem from button code */ + $("#redeemFromBtn").click(function(){ + var redeem = redeemingFrom($("#redeemFrom").val()); + + $("#redeemFromStatus, #redeemFromAddress").addClass('hidden'); + + if(redeem.from=='multisigAddress'){ + $("#redeemFromStatus").removeClass('hidden').html(' This is a multisig address. You must use the redeem script, not the multisig address!'); + return false; + } + + if(redeem.from=='other'){ + $("#redeemFromStatus").removeClass('hidden').html(' The address or multisig redeem script you have entered is invalid'); + return false; + } + + if($("#clearInputsOnLoad").is(":checked")){ + $("#inputs .txidAdd:last").click(); + $("#inputs .txidRemove:not(:last)").click(); + } + + $("#redeemFromBtn").html('Please wait, loading... ').attr('disabled',true); + + var host = $(this).attr('rel'); + providers[$("#coinSelector").val()].listUnspent[host](redeem); + }); + + $("#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"); + } + }); + + /* verify script code */ + + $("#verifyBtn").click(function(){ + $(".verifyData").addClass("hidden"); + $("#verifyStatus").hide(); + if(!decodeRedeemScript()){ + if(!decodeTransactionScript()){ + if(!decodePrivKey()){ + if(!decodePubKey()){ + if(!decodeHDaddress()){ + $("#verifyStatus").removeClass('hidden').fadeOut().fadeIn(); + } + } + } + } + } + + }); + + /* sign code */ + + $("#signBtn").click(function(){ + var wifkey = $("#signPrivateKey"); + if((wifkey.val()).match(/^[a-f0-9]+$/ig)){ + coinjs.compressed = true; + var coint = coinjs.newKeys(wifkey.val(), true); + wifkey.val(coint.wif) + } + 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()); + + var signed = t.sign(wifkey.val()); + $("#signedData textarea").val(signed); + $("#signedData .txSize").html(t.size()); + $("#signedData").removeClass('hidden').fadeIn(); + + $("#signedData .signedToVerify").on( "click", function() { + $("#verifyScript").val(signed).fadeOut().fadeIn(); + $("#verifyBtn").click(); + window.location.hash = "#verify"; + }); + + $("#signedData .signedToBroadcast").on( "click", function() { + $("#broadcast #rawTransaction").val(signed).fadeOut().fadeIn(); + window.location.hash = "#broadcast"; + }); + } catch(e) { + if (coinjs.debug) {console.log(e.stack)}; + } + } else { + $("#signedDataError").removeClass('hidden').delay(2000).queue(function(){ + $(this).addClass("hidden").dequeue(); + }); + $("#signedData").addClass('hidden'); + } + }); + + /* 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(){ + + // log out of openwallet + $("#walletLogout").click(); + + $("#newGeneratedAddress, #newPubKey, #newPrivKeyWif, #newPrivKey, #newHDxpub, #newHDxprv").val(""); + $("#multiSigData, .verifyData").removeClass('show').addClass('hidden'); + + $("#statusSettings").removeClass("alert-success").removeClass("alert-danger").addClass("hidden").html(""); + $("#settings .has-error").removeClass("has-error"); + + $.each($(".coinjssetting"),function(i, o){ + if ($(o).hasClass("boolisvalid")) { + if(!$(o).val().match(/^0x[0-9a-f]+|false$/)){ + $(o).parent().addClass("has-error"); + } + } else { + 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; + + coinjs.txExtraTimeField = ($("#coinjs_extratimefield").val() == "true"); + if (coinjs.txExtraTimeField) { + $("#nTime").val(Date.now() / 1000 | 0); + $("#txTimeOptional").show(); + $("#verifyTransactionData .txtime").show(); + } else { + $("#txTimeOptional").hide(); + $("#verifyTransactionData .txtime").hide(); + } + + coinjs.txExtraUnitField = ($("#coinjs_extraunitfieldvalue").val() !== "false"); + if (coinjs.txExtraUnitField) { + coinjs.txExtraUnitFieldValue = $("#coinjs_extraunitfieldvalue").val()*1; + $("#verifyTransactionData .txunit").show(); + } else { + $("#verifyTransactionData .txunit").hide(); + } + + coinjs.decimalPlaces = $("#coinjs_decimalplaces").val()*1; + coinjs.symbol = $("#coinjs_symbol").val(); + + $("#rawSubmitBtn").attr('rel',$("#coinjs_broadcast option:selected").val()); + $("#redeemFromBtn").attr('rel',$("#coinjs_utxo option:selected").val()); + + toolkit.getInputAmount = $("#coinjs_getinputamount option:selected").val(); + + $("#coinSelector").val($("#coinjs_coin").val()); + + $("#statusSettings").addClass("alert-success").removeClass("hidden").html(" Settings updated successfully").fadeOut().fadeIn().delay(2000).fadeOut(); ; + } else { + $("#statusSettings").addClass("alert-danger").removeClass("hidden").html("There is an error with one or more of your settings"); + } + }); + + + // clear results when data changed + $("#verify #verifyScript").on('input change', function(){ + $("#verify .verifyData").addClass("hidden"); + }); + + $("#sign #signTransaction, #sign #signPrivateKey").on('input change', function(){ + $("#sign #signedData").addClass("hidden"); + }); + + $("#multisigPubKeys .list").on('input change', '.pubkey', function(){ + $("#multiSigData").addClass("hidden"); + }); + + + $("#coinSelector").change(function(){ + $("#coinjs_coin").val(this.value).change(); + $("#settingsBtn").click(); + }); + $("#coinjs_coin").change(function(){ + var o = ($("option:selected",this).attr("rel")).split(";"); + + var mode = this.options[this.selectedIndex].value; + + var walletAvailableUnspent = false; + var walletAvailableBroadcast = false; + + // deal with listUnspent settings` + + $('#coinjs_utxo').empty(); + if(typeof(providers[mode]) == 'object' && typeof(providers[mode].listUnspent) == 'object' && Object.keys(providers[mode].listUnspent).length > 0){ + $.each(providers[mode].listUnspent, function(key) { + $('#coinjs_utxo').append($('').val("disabled"); + + $("#redeemFrom").val("Loading of address inputs is currently not available for " + this.options[ this.selectedIndex ].text); + } + + // deal with input amount settings + $('#coinjs_getinputamount').empty(); + if(typeof(providers[mode]) == 'object' && typeof(providers[mode].getInputAmount) == 'object' && Object.keys(providers[mode].getInputAmount).length > 0){ + $.each(providers[mode].getInputAmount, function(key) { + $('#coinjs_getinputamount').append($('').val("disabled"); + } + + // deal with broadcasting settings + + $('#coinjs_broadcast').empty(); + if(typeof(providers[mode]) == 'object' && typeof(providers[mode].broadcast) == 'object' && Object.keys(providers[mode].broadcast).length > 0){ + $.each(providers[mode].broadcast, function(key) { + $('#coinjs_broadcast').append($('').val("disabled"); + + $("#rawTransaction").val("Transaction broadcasting is currently not available for " + this.options[ this.selectedIndex ].text); + } + + // enable wallet if available + $("#openBtn").attr('disabled', (walletAvailableUnspent && walletAvailableBroadcast)); + + // deal with the reset + $("#coinjs_pub").val(o[0]); + $("#coinjs_multisig").val(o[1]); + $("#coinjs_priv").val(o[2]); + $("#coinjs_hdpub").val(o[3]); + $("#coinjs_hdprv").val(o[4]); + + $("#coinjs_extratimefield").val(o[8]); + $("#coinjs_extraunitfieldvalue").val(o[9]); + + $("#coinjs_decimalplaces").val(o[10]); + $("#coinjs_symbol").val(o[11]); + + // hide/show custom screen + if($("option:selected",this).val()=="custom"){ + $("#settingsCustom").removeClass("hidden"); + } else { + $("#settingsCustom").addClass("hidden"); + } + }); + + /* verify page code*/ + + $("#verifyTransactionData .ins tbody").on( "click", "a[data-index-multisig]", function(e) { + e.preventDefault(); + decodeMultiSig($("#verifyTransactionData .ins tbody").data("tx"), $(this).attr("data-index-multisig")); + }); + + $("#verifyTransactionData .ins tbody").on( "click", "a[data-index-inputscript]", function(e) { + e.preventDefault(); + decodeScript($("#verifyTransactionData .ins tbody").data("tx").ins[$(this).attr("data-index-inputscript")].script); + }); + + $("#verifyTransactionData .outs tbody").on( "click", "a[data-index-outputscript]", function(e) { + e.preventDefault(); + decodeScript($("#verifyTransactionData .ins tbody").data("tx").outs[$(this).attr("data-index-outputscript")].script); + }); + + /* 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; + + $("html").on( "click", "input[readonly]", function () { + this.select(); + }); + + $.each(known.pubKey, function(pubkey, id) { + $('#mediatorList').append($('