forked from dsias/blockchain.info
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sharedcoin.min.js
1 lines (1 loc) · 18 KB
/
sharedcoin.min.js
1
var SharedCoin=new function(){var h=this;var d={};var b=3;var a=MyWallet.getSharedcoinEndpoint()+"?version="+b;var g={};var f="sharedcoin-seed:";function e(o,r){var p=[];var j=Math.round(o*1/r);var q=Math.round(0.5*j);var l=0;for(var k=0;k<r;k++){var m=Math.floor((Math.random()*j)+q);if(l+m>o||k==r-1){m=o-l}l+=m;p[k]=m;if(l==o){break}}return p}var c={show:function(){var i=this;i.modal=$("#sharedcoin-modal");i.modal.modal({keyboard:false,backdrop:"static",show:true});i.modal.find(".btn.btn-secondary").unbind().click(function(){i.hide()})},setAddressAndAmount:function(i,j){if(this.modal){this.modal.find(".total_value").text(formatBTC(j));this.modal.find(".address").text(i)}},hide:function(){if(this.modal){this.modal.modal("hide")}},disableCancel:function(){if(this.modal){this.modal.find(".alert-warning").show();this.modal.find(".alert-error").hide();this.modal.find(".btn.btn-secondary").prop("disabled",true)}},enableCancel:function(){if(this.modal){this.modal.find(".alert-error").show();this.modal.find(".alert-warning").hide();this.modal.find(".btn.btn-secondary").prop("disabled",false)}}};this.newProposal=function(){return{_pollForCompleted:function(k,j){var i=this;console.log("Offer._pollForCompleted()");MyWallet.setLoadingText("Waiting For Other Participants To Sign");$.ajax({dataType:"json",type:"POST",url:a,data:{method:"poll_for_proposal_completed",format:"json",proposal_id:i.proposal_id},success:function(l){k(l)},error:function(l){j(l.responseText)}})},pollForCompleted:function(l,j){var i=this;var k=function(m){if(m.status=="waiting"){i._pollForCompleted(k,j)}else{if(m.status=="not_found"){j("Proposal ID Not Found")}else{if(m.status=="complete"){l(m.tx_hash)}else{j("Unknown status "+m.status)}}}};i._pollForCompleted(k,j)}}};this.newOffer=function(){return{offered_outpoints:[],request_outputs:[],offer_id:0,submit:function(k,j){var i=this;MyWallet.setLoadingText("Submitting Offer");$.ajax({dataType:"json",type:"POST",url:a,data:{method:"submit_offer",format:"json",token:h.getToken(),offer:JSON.stringify(i)},success:function(l){if(!l.offer_id){j("Null offer_id returned")}else{i.offer_id=l.offer_id;k()}},error:function(l){j(l.responseText)}})},_pollForProposalID:function(k,j){var i=this;console.log("Offer._pollForProposalID()");MyWallet.setLoadingText("Waiting For Other Participants");$.ajax({dataType:"json",type:"POST",url:a,data:{method:"get_offer_id",format:"json",offer_id:i.offer_id},success:function(l){k(l)},error:function(l){j(l.responseText)}})},calculateFee:function(){var j=this;var m=BigInteger.ZERO;for(var k in j.offered_outpoints){m=m.add(BigInteger.valueOf(j.offered_outpoints[k].value))}var l=BigInteger.ZERO;for(var k in j.request_outputs){l=l.add(BigInteger.valueOf(j.request_outputs[k].value))}return m.subtract(l)},pollForProposalID:function(l,j){var i=this;var k=function(m){if(m.status=="waiting"){i._pollForProposalID(k,j)}else{if(m.status=="not_found"){j("Offer ID Not Found")}else{if(m.status=="active_proposal"){l(m.proposal_id)}else{j("Unknown status "+m.status)}}}};i._pollForProposalID(k,j)},getProposal:function(k,l,j){var i=this;console.log("SharedCoin.getProposal()");MyWallet.setLoadingText("Fetching Proposal");$.ajax({dataType:"json",type:"POST",url:a,data:{method:"get_proposal_id",format:"json",offer_id:i.offer_id,proposal_id:k},success:function(n){var m=h.newProposal();var o=jQuery.extend(m,n);if(o.status=="not_found"){j("Proposal or Offer ID Not Found")}else{l(o)}},error:function(m){j(m.responseText)}})},isOutpointOneWeOffered:function(j){var i=this;var l=j.outpoint.hash;var o=Crypto.util.bytesToHex(Crypto.util.base64ToBytes(l).reverse());var k=j.outpoint.index;for(var m in i.offered_outpoints){var n=i.offered_outpoints[m];if(n.hash.toString()==o.toString()&&n.index.toString()==k.toString()){return true}}return false},isOutputOneWeRequested:function(k){var j=this;var o=k.value.slice(0);o.reverse();var i=Crypto.util.bytesToHex(k.script.buffer);var n=new BigInteger(o);for(var l in j.request_outputs){var m=j.request_outputs[l];if(m.script.toString()==i.toString()&&n.toString()==m.value.toString()){return true}}return false},isOutputChange:function(k){var j=this;var o=k.value.slice(0);o.reverse();var i=Crypto.util.bytesToHex(k.script.buffer);var n=new BigInteger(o);for(var l in j.request_outputs){var m=j.request_outputs[l];if(m.script.toString()==i.toString()&&n.toString()==m.value.toString()){return m.exclude_from_fee}}return false},checkProposal:function(r,v,s){console.log("Offer.checkProposal()");var x=this;try{if(r.tx==null){throw"Proposal Transaction Is Null"}Bitcoin.Transaction.deserialize=function(H){function z(P){var i,O;i=P.splice(0,1)[0];if(i<253){O=[i]}else{if(i==253){O=P.splice(0,2)}else{if(i==254){O=P.splice(0,4)}else{O=P.splice(0,8)}}}return BigInteger.fromByteArrayUnsigned(O)}function K(i){return new BigInteger(i.splice(0,4).reverse()).intValue()}var J=new Bitcoin.Transaction();J.version=K(H);var D=z(H).intValue();for(var I=0;I<D;I++){var E=H.splice(0,32);var B=Crypto.util.bytesToBase64(E);var y=K(H);var G=z(H).intValue();var L=new Bitcoin.Script(H.splice(0,G));var C=K(H);var M=new Bitcoin.TransactionIn({outpoint:{hash:B,index:y},script:L,sequence:C});J.ins.push(M)}var N=z(H).intValue();for(var I=0;I<N;I++){var A=H.splice(0,8);var G=z(H).intValue();var L=new Bitcoin.Script(H.splice(0,G));var F=new Bitcoin.TransactionOut({script:L,value:A});J.outs.push(F)}J.lock_time=K(H);return J};var m=Crypto.util.hexToBytes(r.tx);var o=Bitcoin.Transaction.deserialize(m);if(o==null){throw"Error deserializing transaction"}var t=[];var w=0;for(var n=0;n<o.outs.length;++n){var l=o.outs[n];if(x.isOutputOneWeRequested(l)){if(!x.isOutputChange(l)){var q=l.value.slice(0);q.reverse();var u=new BigInteger(q);t.push({hash:null,index:parseInt(n),value:u.toString()})}++w}}if(w<x.request_outputs.length){throw"Could not find all our requested outputs ("+w+" < "+x.request_outputs.length+")"}var k=0;for(var n=0;n<r.signature_requests.length;++n){var j=r.signature_requests[n].tx_input_index;if(x.isOutpointOneWeOffered(o.ins[j])){++k}}if(x.offered_outpoints.length!=k){throw"Could not find all our offered outpoints ("+x.offered_outpoints.length+" != "+k+")"}v(o,t)}catch(p){s(p)}},signNormal:function(i,m,o,l){console.log("Offer.signNormal()");var k=0;var n=[];var j=function(){setTimeout(function(){try{var p=m[k];var r=signInput(i,p.tx_input_index,p.priv_to_use,p,SIGHASH_ALL);if(r){k++;n.push({tx_input_index:p.tx_input_index,input_script:Crypto.util.bytesToHex(r.buffer),offer_outpoint_index:p.offer_outpoint_index});if(k==m.length){o(n)}else{j()}}else{throw"Unknown error signing transaction"}}catch(q){l(q)}},1)};j()},submitInputScripts:function(k,l,m,j){console.log("Offer.submitInputScripts()");var i=this;MyWallet.setLoadingText("Submitting Signatures");$.ajax({dataType:"json",type:"POST",url:a,data:{method:"submit_signatures",format:"json",input_scripts:JSON.stringify(l),offer_id:i.offer_id,proposal_id:k.proposal_id},success:function(n){if(n.status=="not_found"){j("Proposal Expired or Not Found")}else{if(n.status=="verification_failed"){j("Signature Verification Failed")}else{if(n.status=="complete"){j("Transaction Already Completed")}else{if(n.status=="signatures_accepted"){m("Signatures Accepted")}else{j("Unknown status "+n.status)}}}}},error:function(n){j(n.responseText)}})},signInputs:function(r,o,u,s){console.log("Offer.signInputs()");var v=this;try{var p={};var k=[];for(var n=0;n<r.signature_requests.length;++n){var m=r.signature_requests[n];var t=new Bitcoin.Script(Crypto.util.hexToBytes(m.connected_script));t.tx_input_index=m.tx_input_index;t.offer_outpoint_index=m.offer_outpoint_index;var j=t.simpleOutPubKeyHash();var l=new Bitcoin.Address(j).toString();if(p[l]){t.priv_to_use=p[l]}else{if(g[l]){t.priv_to_use=Bitcoin.Base58.decode(g[l])}else{if(MyWallet.addressExists(l)&&!MyWallet.isWatchOnly(l)){t.priv_to_use=MyWallet.decodePK(MyWallet.getPrivateKey(l))}}}if(t.priv_to_use==null){throw"Private key not found"}else{p[l]=t.priv_to_use}k.push(t)}v.signNormal(o,k,function(i){u(i)},function(i){s(i)})}catch(q){s(q)}}}};this.generateAddressFromCustomSeed=function(j,m){var l=Crypto.SHA256(j+m,{asBytes:true});var k=new Bitcoin.ECKey(l);if(l[0]%2==0){var i=k.getBitcoinAddress()}else{var i=k.getBitcoinAddressCompressed()}g[i.toString()]=Bitcoin.Base58.encode(k.priv);return i};this.newPlan=function(){return{offers:[],n_stages:0,address_seed:new SecureRandom().nextBytes(16),address_seen_n:0,generateAddressFromSeed:function(){if(this.address_seed==null){var j=[];j.length=18;new SecureRandom().nextBytes(j);this.address_seed=Crypto.util.bytesToHex(j);MyWallet.addAdditionalSeeds(f+this.address_seed)}var i=h.generateAddressFromCustomSeed(f+this.address_seed,this.address_seen_n);this.address_seen_n++;return i},executeOffer:function(j,k,i){j.submit(function(){console.log("Successfully Submitted Offer");j.pollForProposalID(function(l){console.log("Proposal ID "+l);j.getProposal(l,function(m){console.log("Got Proposal");j.checkProposal(m,function(n,o){console.log("Proposal Looks Good");j.signInputs(m,n,function(p){console.log("Inputs Signed");j.submitInputScripts(m,p,function(q){console.log("Submitted Input Scripts");m.pollForCompleted(function(s){console.log("Poll For Completed Success");for(var r in o){o[r].hash=s}k(o)},i)},i)},i)},i)},i)},i)},i)},execute:function(l,j){var i=this;var k=function(m){var n=i.offers[m];console.log("Executing Stage "+m);i.executeOffer(n,function(o){m++;if(m<i.n_stages){i.offers[m].offered_outpoints=o;k(m)}else{if(m==i.n_stages){l()}}},j)};MyWallet.backupWallet("update",function(){console.log("Saved Wallet");k(0)},j)},constructRepetitions:function(n,s,t,G){try{var D=this;var u=BigInteger.ZERO;for(var H in n.offered_outpoints){u=u.add(BigInteger.valueOf(n.offered_outpoints[H].value))}var m=u;for(var z=0;z<D.n_stages-1;++z){var k=h.newOffer();if(z==0){for(var H in n.request_outputs){if(n.request_outputs[H].exclude_from_fee){var x=n.request_outputs.splice(H,1)[0];k.request_outputs.push(x);m=m.subtract(BigInteger.valueOf(x.value));break}}k.offered_outpoints=n.offered_outpoints.slice(0);n.offered_outpoints=[]}m=m.subtract(s[z]);var r=[10,5,1,0.5,0.3,0.1];var A=10;var J=Math.random();if(m.intValue()>=0.2*satoshi){var E=2;if(J>=0.5){E=3}}else{var E=1}var v=false;for(var l=0;l<1000;++l){for(var B in r){var q=(r[B]/100)*((Math.random()*30)-15);var o=BigInteger.valueOf(Math.round((r[B]+q)*satoshi));var y=m.divideAndRemainder(o);var j=y[0].intValue();if(j>=E&&j<=A){if(y[1].compareTo(BigInteger.ZERO)==0||y[1].compareTo(BigInteger.valueOf(h.getMinimumOutputValue()))>=0){var w=[];if(y[1].compareTo(BigInteger.ZERO)>0){if(j<=1){var p=D.generateAddressFromSeed();k.request_outputs.push({value:y[1].toString(),script:Crypto.util.bytesToHex(Script.createOutputScript(p).buffer)})}else{w=e(y[1].intValue(),j)}}for(var C=0;C<j;++C){var p=D.generateAddressFromSeed();var F=o;if(w[C]&&w[C]>0){F=F.add(BigInteger.valueOf(w[C]))}k.request_outputs.push({value:F.toString(),script:Crypto.util.bytesToHex(Script.createOutputScript(p).buffer)})}v=true;break}}}if(v){break}}if(!v){console.log("Could not successfully split output");var p=D.generateAddressFromSeed();k.request_outputs.push({value:m.toString(),script:Crypto.util.bytesToHex(Script.createOutputScript(p).buffer)})}D.offers.push(k)}D.offers.push(n);t(D)}catch(I){G(I)}}}};this.generateNewAddress=function(m,i){try{var j=MyWallet.generateNewKey();var l=j.getBitcoinAddress();MyWallet.setAddressLabel(l.toString(),"SharedCoin Change");m(l)}catch(k){i(k)}};this.getMinimumOutputValue=function(){return d.minimum_output_value};this.getToken=function(){return d.token};this.getMinimumInputValue=function(){return d.minimum_input_value};this.getMinimumSupportedVersion=function(){return d.min_supported_version};this.getIsEnabled=function(){return d.enabled};this.getMaximumOutputValue=function(){return d.maximum_output_value};this.getFee=function(){return d.fee_percent};this.getMinimumFee=function(){return d.minimum_fee?d.minimum_fee:0};this.constructPlan=function(o,z,w){try{var l=o.find('select[name="repetitions"]');var s=parseInt(l.val());if(s<=0){throw"invalid number of repetitions"}var t=initNewTx();var j=o.find('select[name="from"]');var p=j.val();if(p==null||p=="any"){t.from_addresses=MyWallet.getActiveAddresses()}else{if(j.attr("multiple")=="multiple"){t.from_addresses=p}else{t.from_addresses=[p]}}var k=o.find(".recipient");k.each(function(){try{var F=$(this);var E=F.find('input[name="send-value"]');var B=F.find('input[name="send-to-address"]');var C=0;try{C=precisionToSatoshiBN(E.val());if(C==null||C.compareTo(BigInteger.ZERO)<=0){throw"You must enter a value greater than zero"}}catch(D){throw"Invalid send amount"}var i=$.trim(B.val()).replace(/[\u200B-\u200D\uFEFF]/g,"");if(i==null||i.length==0){throw"You must enter a bitcoin address for each recipient"}var A=resolveAddress(i);if(A==null||A.length==0){throw"You must enter a bitcoin address for each recipient"}t.to_addresses.push({address:new Bitcoin.Address(A),value:C})}catch(D){w(D)}});if(t.to_addresses.length==0||t.to_addresses.length<k.length){return}var n=[];var x=[];for(var r in t.to_addresses){var q=t.to_addresses[r];n.push(q.value);for(var y=s-1;y>=0;--y){var v=h.calculateFeeForValue(q.value);q.value=q.value.add(v);var m=x[y];if(m){x[y]=m.add(v)}else{x[y]=v}}}h.generateNewAddress(function(i){t.min_input_confirmations=1;t.allow_adjust=false;t.change_address=i;t.base_fee=BigInteger.ZERO;t.min_input_size=BigInteger.valueOf(h.getMinimumInputValue());t.min_free_output_size=BigInteger.valueOf(h.getMinimumOutputValue());t.fee=BigInteger.ZERO;t.ask_for_fee=function(C,B){B()};var A=h.newOffer();t.signInputs=function(){try{var M=this;for(var E=0;E<M.tx.ins.length;++E){var K=M.tx.ins[E];var C=K.outpoint.hash;var J=Crypto.util.bytesToHex(Crypto.util.base64ToBytes(C).reverse());A.offered_outpoints.push({hash:J,index:K.outpoint.index,value:K.outpoint.value.toString()})}for(var E=0;E<M.tx.outs.length;++E){var D=M.tx.outs[E];var H=D.value.slice(0);H.reverse();var L=new BigInteger(H);var B=new Bitcoin.Script(D.script).simpleOutPubKeyHash();var G=new Bitcoin.Address(B).toString();if(G.toString()==i.toString()){A.request_outputs.push({value:L.toString(),script:Crypto.util.bytesToHex(D.script.buffer),exclude_from_fee:true})}else{A.request_outputs.push({value:n[E].toString(),script:Crypto.util.bytesToHex(D.script.buffer)})}}var I=h.newPlan();I.n_stages=s;I.c_stage=0;I.constructRepetitions(A,x,z,function(N){w(N)})}catch(F){w(F)}};t.addListener({on_error:function(B){w()}});t.start()},function(i){w(i)})}catch(u){MyWallet.makeNotice("error","misc-error",u)}};this.calculateFeeForValue=function(j){var k=BigInteger.valueOf(h.getMinimumFee());if(j.compareTo(BigInteger.ZERO)>0&&h.getFee()>0){var l=Math.ceil(100/h.getFee());var i=j.divide(BigInteger.valueOf(l));if(k.compareTo(i)>0){return k}else{return i}}else{return k}};this.init=function(k){$("#sharedcoin-recover").unbind().click(function(){var o=$(this);MyWallet.getSecondPassword(function(){o.prop("disabled",true);var s=o.text();o.text("Working. Please Wait...");var v=MyWallet.getAdditionalSeeds();var p=[];for(var r in v){var q=v[r];if(q.indexOf(f)==0){p.push(q)}}var r=0;var u=[];function t(){var w=p[r];++r;for(var x=0;x<50;++x){u.push(h.generateAddressFromCustomSeed(w,x).toString())}if(r==p.length){while(u.length>0){(function(y){BlockchainAPI.get_balances(y,function(C){o.prop("disabled",false);o.text(s);var D=0;for(var B in C){var A=B;var E=C[A].final_balance;if(E>0){var z=new Bitcoin.ECKey(Bitcoin.Base58.decode(g[A]));var A=z.getBitcoinAddress().toString();if(MyWallet.addPrivateKey(z,{compressed:A!=B,app_name:IMPORTED_APP_NAME,app_version:IMPORTED_APP_VERSION})){console.log("Imported "+A)}}D+=E}MyWallet.makeNotice("success","misc-success",formatBTC(D)+" recovered from intermediate addresses");if(D>0){MyWallet.backupWalletDelayed("update",function(){MyWallet.get_history()})}},function(z){o.prop("disabled",false);o.text(s);MyWallet.makeNotice("error","misc-error",z)})})(u.splice(0,1000))}}else{setTimeout(t,100)}}setTimeout(t,100)})});var n=k.find(".send");var l=k.find(".send-options");var j=k.find('select[name="repetitions"]');n.unbind().prop("disabled",true);k.find('input[name="send-value"]').bind("keyup change",function(){i()});l.hide();function m(){var o=l.find("span");o.eq(0).text(formatBTC(h.getMaximumOutputValue()));o.eq(1).text(formatBTC(h.getMinimumOutputValue()));o.eq(2).text(h.getFee());o.eq(3).text(formatBTC(h.getMinimumFee()));l.show()}function i(){var p=parseInt(j.val());if(p>0&&h.getIsEnabled()&&b>=h.getMinimumSupportedVersion()){var o=precisionToSatoshiBN(k.find('input[name="send-value"]').val());if(o.compareTo(BigInteger.valueOf(h.getMinimumOutputValue()))<0){n.prop("disabled",true)}else{if(o.compareTo(BigInteger.valueOf(h.getMaximumOutputValue()))>0){n.prop("disabled",true)}else{n.prop("disabled",false);n.unbind().click(function(){MyWallet.disableLogout(true);var q=function(s){k.find("input,select,button").prop("disabled",false);i();MyWallet.disableLogout(false);MyWallet.makeNotice("error","misc-error",s);c.enableCancel()};var r=function(){k.find("input,select,button").prop("disabled",false);MyWallet.makeNotice("success","misc-success","Sharedcoin Transaction Successfully Completed");MyWallet.disableLogout(false);c.hide();i()};MyWallet.getSecondPassword(function(){loadScript("wallet/signer",function(){c.show();c.disableCancel();var t=precisionToSatoshiBN(k.find('input[name="send-value"]').val());var s=k.find('input[name="send-to-address"]').val();c.setAddressAndAmount(s,t);k.find("input,select,button").prop("disabled",true);h.constructPlan(k,function(u){console.log("Created Plan");console.log(u);u.execute(r,q)},q)},q)},q)})}}}else{n.prop("disabled",true)}}if($.isEmptyObject(d)){MyWallet.setLoadingText("Fetching SharedCoin Info");$.ajax({dataType:"json",type:"POST",url:a,data:{method:"get_info",format:"json"},success:function(q){try{d=q;if(!h.getIsEnabled()){throw"Shared Coin is currently disabled"}if(b<h.getMinimumSupportedVersion()){throw"Version out of date. Please update your client or reload the page."}m();j.empty();for(var o=q.recommended_min_iterations;o<=q.recommended_max_iterations;o+=1){j.append('<option value="'+(o)+'">'+(o)+" Repetitions (Fee: "+((o)*h.getFee()).toFixed(2)+"%)</option>")}j.val(q.recommended_iterations)}catch(p){MyWallet.makeNotice("error","misc-error",p)}i()},error:function(o){n.prop("disabled",true);MyWallet.makeNotice("error","misc-error",o.responseText)}})}else{m()}}};