This repository has been archived by the owner on Apr 20, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 127
/
sharedcoin.min.js
1 lines (1 loc) · 33.4 KB
/
sharedcoin.min.js
1
var SharedCoin=new function(){var u=this;var w=0.5;var x=1;var h=120000;var d=3;var o=0;var f=120000;var a={};var c=6;var g;var s={};var i="sharedcoin-seed-v2:";var e="sharedcoin-seed:";var l=7;function p(A){var z=0,y;for(y in A){z++}return z}function j(B){var y=B.split("\n");var A="";for(var z in y){A+=" "+y[z]+"\n"}return A}function n(C,E){if(E==0){throw"Invalid N"}var y=[];var B=BigInteger.ZERO;for(var A=0;A<E;++A){y[A]=C.multiply(BigInteger.valueOf(Math.round(Math.random()*100)));B=B.add(y[A])}var z=B.divide(C);B=BigInteger.ZERO;for(var A=0;A<E;++A){y[A]=y[A].divide(z);B=B.add(y[A])}var D=Math.ceil(Math.random()*y.length)-1;y[D]=y[D].add(C.subtract(B));return y}function q(A){var z=Math.log(2)/Math.log(10);var y=Math.ceil((z*A.bitLength()+1));if(BigInteger.valueOf(10).pow(BigInteger.valueOf(y-1)).compareTo(A)>0){return y-1}return y}function m(z,A){return Math.round(z+(Math.random()*(A-z)))}function r(F,C,E){var B=F.add(C);var z=q(F);E=Math.min(z-1,E);var y=BigInteger.valueOf(Math.pow(10,m(1,z-1)));var A=F.divide(y).multiply(y);var D=B.subtract(A);return[A,D]}function t(A){var B=3600*1000;var E=60*1000;var y=Math.floor(A/B);var z=Math.floor((A-(y*B))/E);var D=Math.round((A-(y*B)-(z*E))/1000);var C="";if(z>0){C+=z+" minutes"}if(D>0){C+=(C.length>0?" ":"")+D+" seconds"}return C}(function(y){y.retryAjax=function(A){var z;A.tryCount=(!A.tryCount)?0:A.tryCount;A.retryLimit=(!A.retryLimit)?2:A.retryLimit;A.suppressErrors=true;if(A.error){z=A.error;delete A.error}else{z=function(){}}A.complete=function(B,C){if(y.inArray(C,["timeout","abort","error"])>-1){this.tryCount++;if(this.tryCount<=this.retryLimit){if(this.tryCount===this.retryLimit){this.error=z;delete this.suppressErrors}(function(D){setTimeout(function(){y.ajax(D)},5000)})(this);return true}return true}};y.ajax(A)}}(jQuery));Bitcoin.Transaction.deserialize=function(H){function z(Q){var O,P;O=Q.splice(0,1)[0];if(O<253){P=[O]}else{if(O==253){P=Q.splice(0,2)}else{if(O==254){P=Q.splice(0,4)}else{P=Q.splice(0,8)}}}return BigInteger.fromByteArrayUnsigned(P)}function K(O){return new BigInteger(O.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};function b(C,F){var D=[];var y=Math.round(C*1/F);var E=Math.round(0.5*y);var A=0;for(var z=0;z<F;z++){var B=Math.floor((Math.random()*y)+E);if(A+B>C||z==F-1){B=C-A}A+=B;D[z]=B;if(A==C){break}}return D}var k={show:function(A,B,z){var y=this;y.modal=$("#sharedcoin-review-modal");y.success=B;y.error=z;y.modal.modal({keyboard:false,backdrop:"static",show:true});y.modal.find(".btn.btn-primary").unbind().click(function(){y.success();y.hide()});y.modal.find(".btn.btn-secondary").unbind().click(function(){y.error();y.hide()});y.setPlan(A)},hide:function(){if(this.modal){this.modal.modal("hide");this.success=null;this.error=null}},setPlan:function(A){if(this.modal){this.modal.find(".estimated-time").text(t(A.getEstimatedTimeLeft()));this.modal.find(".n-repetitions").text(A.offers.length);this.modal.find(".network-fees").text(formatBTC(A.offers.length*u.getMinimumFee()));this.modal.find(".total-fee").text(formatBTC(A.calculateTotalFee().toString()));var B=this.modal.find(".to");B.empty();for(var y in A.to_addresses){var z=A.to_addresses[y];B.append(y+" ("+formatBTC(z.toString())+")<br/>")}}}};var v={show:function(){var y=this;y.modal=$("#sharedcoin-modal");y.modal.modal({keyboard:false,backdrop:"static",show:true});y.modal.find(".btn.btn-secondary").unbind().click(function(){y.hide()})},setEstimatedTime:function(y){if(this.modal){var z=this.modal.find(".estimated-time");var A=this.modal.find("h3").find("small");if(y<=0){z.hide();A.hide()}else{A.show();z.show();z.text(t(y))}}},setProgressError:function(){if(this.modal){var y=this.modal.find(".progress");y.addClass("progress-danger");y.removeClass("progress-success");y.removeClass("progress-info")}},setProgressSuccess:function(){if(this.modal){var y=this.modal.find(".progress");y.addClass("progress-success");y.removeClass("progress-danger");y.removeClass("progress-info")}},setProgressInfo:function(){if(this.modal){var y=this.modal.find(".progress");y.addClass("progress-info");y.removeClass("progress-success");y.removeClass("progress-danger")}},setProgress:function(z,B){if(this.modal){var A=(z/B)*100;var y=this.modal.find(".progress");if(z>=B){y.removeClass("active")}else{y.addClass("active")}y.children().css("width",A+"%")}},setAddressAndAmount:function(y,z){if(this.modal){this.modal.find(".total_value").text(formatBTC(z));this.modal.find(".address").text(y)}},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(A,z){var y=this;console.log("Offer._pollForCompleted()");MyWallet.setLoadingText("Waiting For Other Participants To Sign");$.retryAjax({dataType:"json",type:"POST",url:g,timeout:h,retryLimit:4,data:{method:"poll_for_proposal_completed",format:"json",proposal_id:y.proposal_id},success:function(B){A(B)},error:function(B){z(B.responseText)}})},pollForCompleted:function(B,z){var y=this;var A=function(C){if(C.status=="waiting"){y._pollForCompleted(A,z)}else{if(C.status=="not_found"){z("Proposal ID Not Found")}else{if(C.status=="complete"){B(C.tx_hash,C.tx)}else{z("Unknown status "+C.status)}}}};y._pollForCompleted(A,z)}}};this.newOffer=function(){return{offered_outpoints:[],request_outputs:[],offer_id:0,fee_percent:0,wait_time:60000,time_submitted:0,toString:function(){var z=this;var E="---- OFFER ----\n";E+="ID "+z.offer_id+"\n";E+="Fee Percent "+z.fee_percent+"\n";E+="Actual Fee "+z.calculateFee()+"\n";E+="Wait Time "+z.wait_time+"\n";E+="Inputs [\n";for(var A in z.offered_outpoints){var D=z.offered_outpoints[A];if(D.hash==null){var y=new Script(Crypto.util.hexToBytes(D.script));var C=[];y.extractAddresses(C);E+=" Awaiting Connection (Address "+C[0]+")"}else{E+=" Hash : "+D.hash}E+=" Value : "+D.value;E+="\n"}E+="]\n";E+="Outputs [\n";for(var A in z.request_outputs){var B=z.request_outputs[A];var y=new Script(Crypto.util.hexToBytes(B.script));var C=[];y.extractAddresses(C);E+=" Address : "+C[0]+" Value : "+B.value;if(B.exclude_from_fee){E+=" Change Output"}E+="\n"}E+="]\n";E+="---- END OFFER ----";return E},submit:function(B,A,y){var z=this;z.time_submitted=new Date().getTime();MyWallet.setLoadingText("Submitting Offer");$.retryAjax({dataType:"json",type:"POST",url:g,timeout:h,retryLimit:d,data:{method:"submit_offer",fee_percent:z.fee_percent,format:"json",token:u.getToken(),offer:JSON.stringify(z),offer_max_age:z.wait_time},success:function(C){if(C.status=="complete"){y(C.tx_hash,C.tx)}else{if(!C.offer_id){A("Null offer_id returned")}else{z.offer_id=C.offer_id;B()}}},error:function(C){A(C.responseText)}})},_pollForProposalID:function(A,z){var y=this;console.log("Offer._pollForProposalID()");MyWallet.setLoadingText("Waiting For Outputs To Be Joined");$.retryAjax({dataType:"json",type:"POST",url:g,timeout:h,retryLimit:d,data:{method:"get_offer_id",format:"json",offer_id:y.offer_id},success:function(B){A(B)},error:function(B){z(B.responseText)}})},calculateFee:function(){var y=this;var B=BigInteger.ZERO;for(var z in y.offered_outpoints){B=B.add(BigInteger.valueOf(y.offered_outpoints[z].value))}var A=BigInteger.ZERO;for(var z in y.request_outputs){A=A.add(BigInteger.valueOf(y.request_outputs[z].value))}return B.subtract(A)},pollForProposalID:function(B,z){var y=this;var A=function(C){if(C.status=="waiting"){y._pollForProposalID(A,z)}else{if(C.status=="not_found"){z("Offer ID Not Found")}else{if(C.status=="active_proposal"){B(C.proposal_id)}else{z("Unknown status "+C.status)}}}};y._pollForProposalID(A,z)},getProposal:function(B,C,A,y){var z=this;console.log("SharedCoin.getProposal()");MyWallet.setLoadingText("Fetching Proposal");$.retryAjax({dataType:"json",type:"POST",url:g,timeout:h,retryLimit:d,data:{method:"get_proposal_id",format:"json",offer_id:z.offer_id,proposal_id:B},success:function(E){var D=u.newProposal();var F=jQuery.extend(D,E);if(F.status=="not_found"){A("Proposal or Offer ID Not Found")}else{if(F.status=="complete"){y(F.tx_hash,F.tx)}else{if(F.status=="signatures_needed"){C(F)}else{if(F.status=="waiting"){z.getProposal(B,C,A,y)}else{A("Unknown get_proposal_id status")}}}}},error:function(D){A(D.responseText)}})},isOutpointOneWeOffered:function(z){var y=this;var B=z.outpoint.hash;var E=Crypto.util.bytesToHex(Crypto.util.base64ToBytes(B).reverse());var A=z.outpoint.index;for(var C in y.offered_outpoints){var D=y.offered_outpoints[C];if(D.hash.toString()==E.toString()&&D.index.toString()==A.toString()){return true}}return false},isOutputOneWeRequested:function(A){var z=this;var E=A.value.slice(0);E.reverse();var y=Crypto.util.bytesToHex(A.script.buffer);var D=new BigInteger(E);for(var B in z.request_outputs){var C=z.request_outputs[B];if(C.script.toString()==y.toString()&&D.toString()==C.value.toString()){return true}}return false},isOutputChange:function(A){var z=this;var E=A.value.slice(0);E.reverse();var y=Crypto.util.bytesToHex(A.script.buffer);var D=new BigInteger(E);for(var B in z.request_outputs){var C=z.request_outputs[B];if(C.script.toString()==y.toString()&&D.toString()==C.value.toString()){return C.exclude_from_fee}}return false},determineOutputsToOfferNextStage:function(J,E,I,F){var K=this;try{var z=Crypto.util.hexToBytes(E);var B=Bitcoin.Transaction.deserialize(z);var G=[];for(var A=0;A<B.outs.length;++A){var y=B.outs[A];if(K.isOutputOneWeRequested(y)){if(!K.isOutputChange(y)){var D=y.value.slice(0);D.reverse();var H=new BigInteger(D);G.push({script:Crypto.util.bytesToHex(y.script.buffer),hash:J,index:parseInt(A),value:H.toString()})}}}I(G)}catch(C){F(C)}},checkProposal:function(F,H,G){console.log("Offer.checkProposal()");var J=this;try{if(F.tx==null){throw"Proposal Transaction Is Null"}var B=Crypto.util.hexToBytes(F.tx);var D=Bitcoin.Transaction.deserialize(B);if(D==null){throw"Error deserializing transaction"}var I=0;for(var C=0;C<D.outs.length;++C){var A=D.outs[C];if(J.isOutputOneWeRequested(A)){++I}}if(I<J.request_outputs.length){throw"Could not find all our requested outputs ("+I+" < "+J.request_outputs.length+")"}var z=0;for(var C=0;C<F.signature_requests.length;++C){var y=F.signature_requests[C].tx_input_index;if(J.isOutpointOneWeOffered(D.ins[y])){++z}}if(J.offered_outpoints.length!=z){throw"Could not find all our offered outpoints ("+J.offered_outpoints.length+" != "+z+")"}H(D)}catch(E){G(E)}},signNormal:function(y,C,E,B){console.log("Offer.signNormal()");var A=0;var D=[];var z=function(){setTimeout(function(){try{var F=C[A];if(F==null){throw"Null connected script"}var H=signInput(y,F.tx_input_index,F.priv_to_use,F,SIGHASH_ALL);if(H){A++;D.push({tx_input_index:F.tx_input_index,input_script:Crypto.util.bytesToHex(H.buffer),offer_outpoint_index:F.offer_outpoint_index});if(A==C.length){E(D)}else{z()}}else{throw"Unknown error signing transaction"}}catch(G){B(G)}},1)};z()},submitInputScripts:function(B,C,D,A,y){console.log("Offer.submitInputScripts()");var z=this;MyWallet.setLoadingText("Submitting Signatures");o=new Date().getTime();$.retryAjax({dataType:"json",type:"POST",url:g,timeout:h,retryLimit:d,data:{method:"submit_signatures",format:"json",input_scripts:JSON.stringify(C),offer_id:z.offer_id,proposal_id:B.proposal_id},success:function(E){if(E.status=="not_found"){A("Proposal Expired or Not Found")}else{if(E.status=="verification_failed"){A("Signature Verification Failed")}else{if(E.status=="complete"){y(E.tx_hash,E.tx)}else{if(E.status=="signatures_accepted"){D("Signatures Accepted")}else{A("Unknown status "+E.status)}}}}},error:function(E){A(E.responseText)}})},signInputs:function(G,D,J,H){console.log("Offer.signInputs()");var K=this;try{var E={};var z=[];for(var C=0;C<G.signature_requests.length;++C){var B=G.signature_requests[C];var I=new Bitcoin.Script(Crypto.util.hexToBytes(B.connected_script));if(I==null){throw"signInputs() Connected script is null"}I.tx_input_index=B.tx_input_index;I.offer_outpoint_index=B.offer_outpoint_index;var y=I.simpleOutPubKeyHash();var A=new Bitcoin.Address(y).toString();if(E[A]){I.priv_to_use=E[A]}else{if(s[A]){I.priv_to_use=Bitcoin.Base58.decode(s[A])}else{if(MyWallet.addressExists(A)&&!MyWallet.isWatchOnly(A)){I.priv_to_use=MyWallet.decodePK(MyWallet.getPrivateKey(A))}}}if(I.priv_to_use==null){throw"Private key not found"}else{E[A]=I.priv_to_use}z.push(I)}K.signNormal(D,z,function(L){J(L)},function(L){H(L)})}catch(F){H(F)}}}};this.generateAddressAndKeyFromCustomSeed=function(z,C){var B=Crypto.SHA256(z+C,{asBytes:true});var A=new Bitcoin.ECKey(B);if(z.indexOf(i)==0){var y=A.getBitcoinAddressCompressed()}else{if(B[0]%2==0){var y=A.getBitcoinAddress()}else{var y=A.getBitcoinAddressCompressed()}}return{address:y,key:A}};this.generateAddressFromCustomSeed=function(z,A){var y=this.generateAddressAndKeyFromCustomSeed(z,A);s[y.address.toString()]=Bitcoin.Base58.encode(y.key.priv);return y.address};this.newPlan=function(){return{offers:[],c_stage:0,address_seed:null,address_seen_n:0,generated_addresses:[],fee_percent_each_repetition:[],fee_each_repetition:[],to_addresses:{},generateAddressFromSeed:function(){if(this.address_seed==null){MyWallet._seed();var z=new Array(18);new SecureRandom().nextBytes(z);this.address_seed=Crypto.util.bytesToHex(z);MyWallet.addAdditionalSeeds(i+this.address_seed)}if(this.address_seen_n>=100){throw"Generating An Address Seed Greater than 100 Index. Please file an issue on Shared Coin github"}var y=u.generateAddressFromCustomSeed(i+this.address_seed,this.address_seen_n);this.address_seen_n++;return y},sanityCheck:function(E,N){try{var K=this;if(K.offers.length==0){throw"No Offers"}var B=BigInteger.valueOf(u.getMinimumFee());var J=$.extend({},K.to_addresses);for(var O in K.offers){var y=K.offers[O];var F=BigInteger.ZERO;var Q=BigInteger.ZERO;if(y.offered_outpoints.length>u.getMaximumOfferNumberOfInputs()){throw"Number of inputs greater than maximum"}for(var I in y.offered_outpoints){var H=y.offered_outpoints[I];if(H.value<u.getMinimumInputValue()){throw"Input value less than minimum"}if(H.value>u.getMaximumInputValue()){throw"Input value greater than maximum"}F=F.add(BigInteger.valueOf(H.value))}if(y.request_outputs.length>u.getMaximumOfferNumberOfOutputs()){throw"Number of outputs greater than maximum"}var z=BigInteger.ZERO;for(var I in y.request_outputs){var D=y.request_outputs[I];if(!D.script){throw"Output script null"}if(D.value<=0){throw"Output value <= 0"}if(D.exclude_from_fee){if(D.value<u.getMinimumOutputValueExcludingFee()){throw"Output value less than minimum value excluding fee"}}else{if(D.value<u.getMinimumOutputValue()){throw"Output value less than minimum"}if(D.value>u.getMaximumOutputValue()){throw"Output value greater than maximum"}}var R=new Script(Crypto.util.hexToBytes(D.script));var A=[];R.extractAddresses(A);if(A.length>1){throw"Multiple output addresses"}var C=A[0].toString();var G=BigInteger.valueOf(D.value);if(J[C]){if(J[C].compareTo(G)!=0){throw"Wrong Value Sent To "+C}else{delete J[C]}}else{if(MyWallet.addressExists(C)){}else{if(s[C]){}else{throw"Unknown Address "+C}}}Q=Q.add(G);if(!D.exclude_from_fee){z=z.add(G)}}if(F.compareTo(Q)<0){throw"valueInput < valueOutput"}var M=F.subtract(Q);if(M.compareTo(B)<0){throw"Fee is too small"}if(M.compareTo(BigInteger.valueOf(satoshi))>0){throw"Fee seems unusually large"}var L=u.calculateFeeForValue(y.fee_percent,z);if(M.compareTo(L.add(B))>0){throw"Fee greater than expected"}if(z.compareTo(BigInteger.valueOf(u.getMaxTotalFeePayingOutputValue()))>0){throw"Fee paying output value greater than maximum"}}if(p(J)!=0){throw"Some recipient outputs missing"}E()}catch(P){console.log(P);N("Sanity Check Failed "+P+" : Please report to developers")}},toString:function(){var y=this;var A="----- PLAN -----\n";A+="fee_percent_each_repetition "+y.fee_percent_each_repetition+"\n";A+="fee_each_repetition "+y.fee_each_repetition+"\n";A+="address_seen_n "+y.address_seen_n+"\n";A+="address_seed "+y.address_seed+"\n";A+="generated_addresses "+y.generated_addresses+"\n";A+="Offers [\n";for(var z in y.offers){A+=j(y.offers[z].toString())+"\n"}A+="]\n";A+="----- END PLAN -----";return A},calculateTotalFee:function(){var y=this;var z=BigInteger.ZERO;for(var A in y.offers){z=z.add(y.offers[A].calculateFee())}return z},generateChangeAddress:function(){var z=MyWallet.generateNewKey();if(!z||!z.addr){throw"Error Generating Change Address"}var y=z.addr;this.generated_addresses.push(y);return new Bitcoin.Address(y)},getEstimatedTimeLeft:function(){var y=this;var A=0;for(var z=y.c_stage;z<y.offers.length;++z){var B=y.offers[z];A+=10000;if(z==y.c_stage&&B.time_submitted>0){A+=Math.max(B.wait_time-(new Date().getTime()-B.time_submitted),0)}else{A+=B.wait_time}}return A},executeOffer:function(C,D,A,z){function y(F,E){console.log("executeOffer.complete");C.determineOutputsToOfferNextStage(F,E,function(G){D(G)},A)}var B=0;z(++B,l);C.submit(function(){console.log("Successfully Submitted Offer");z(++B,l);C.pollForProposalID(function(E){console.log("Proposal ID "+E);z(++B,l);C.getProposal(E,function(F){console.log("Got Proposal");z(++B,l);C.checkProposal(F,function(G){console.log("Proposal Looks Good");z(++B,l);C.signInputs(F,G,function(H){console.log("Inputs Signed");z(++B,l);C.submitInputScripts(F,H,function(I){console.log("Submitted Input Scripts");z(++B,l);F.pollForCompleted(y,A)},A,y)},A)},A)},A,y)},A)},A,y)},execute:function(C,A,z){var y=this;var B=function(F){y.c_stage=F;var H=y.offers[F];console.log("Executing Stage "+F);var G=function(N){try{F++;if(F<y.offers.length){var L=y.offers[F];for(var J in N){var P=N[J];for(var K in L.offered_outpoints){var O=L.offered_outpoints[K];if(P.script==O.script&&P.value==O.value){$.extend(O,P);break}}}B(F)}else{if(F==y.offers.length){C()}}}catch(M){A(M)}};for(var I in H.offered_outpoints){var E=H.offered_outpoints[I];if(!E.hash){throw"Failed to connect input "+F}}var D=function(J){z(J+(l*y.c_stage),l*y.offers.length)};y.executeOffer(H,G,function(J){console.log("executeOffer failed "+J);setTimeout(function(){y.executeOffer(H,G,A,D)},5000)},D)};MyWallet.backupWallet("update",function(){console.log("Saved Wallet");var G=MyWallet.getAdditionalSeeds();var F=false;for(var E in G){var D=G[E];if(D.indexOf(y.address_seed)>=0){F=true;break}}if(!F){A("Address Seed Not Found")}else{B(0)}},A)},constructOffers:function(H,L,R,D,C,M,X){try{var V=this;var N=BigInteger.ZERO;for(var Z in H.offered_outpoints){N=N.add(BigInteger.valueOf(H.offered_outpoints[Z].value))}var E=N.subtract(L);var S=L;H.fee_percent=V.fee_percent_each_repetition[V.fee_percent_each_repetition.length-1];H.wait_time=D;var Q;for(var U=0;U<R-1;++U){var z=u.newOffer();z.wait_time=D;if(U==0){z.offered_outpoints=H.offered_outpoints.slice(0);H.offered_outpoints=[]}else{for(var A in Q.request_outputs){var B=Q.request_outputs[A];if(!B.exclude_from_fee){z.offered_outpoints.push(B)}}}z.fee_percent=V.fee_percent_each_repetition[U];E=E.subtract(V.fee_each_repetition[U]);var ac=BigInteger.ZERO;if(S.compareTo(BigInteger.ZERO)<0){throw"totalChangeValueLeftToConsume < 0"}else{if(S.compareTo(BigInteger.ZERO)>0){var Y=Math.min(Math.max(R-2,1),C);var G=(100/Y)*((Math.random()*0.5)+0.75);ac=L.divide(BigInteger.valueOf(100)).multiply(BigInteger.valueOf(Math.ceil(G)))}}if(ac.compareTo(BigInteger.valueOf(u.getMinimumOutputValue()))<=0||S.subtract(ac).compareTo(BigInteger.valueOf(u.getMinimumOutputValue()))<=0){ac=S;S=BigInteger.ZERO}else{S=S.subtract(ac)}if(S.compareTo(BigInteger.ZERO)<0){throw"totalChangeValueLeftToConsume < 0"}var F=E.add(S);var P=F.subtract(BigInteger.valueOf(u.getMaxTotalFeePayingOutputValue()));if(P.compareTo(BigInteger.ZERO)>0){F=F.subtract(P);ac=ac.add(P);S=S.subtract(P)}var T=u.getMaxOutputSplits();var W=u.getMinOutputSplits();if(F.compareTo(BigInteger.valueOf(u.getMinimumOutputValue()*(u.getMinOutputSplits()+1)))<0){W=1}var O=[];while(true){var aa=Math.round((Math.random()*(T-W))+W);var y=n(F,aa);if(y.length>1){var ad=r(y[0],y[1],u.getRandomRoundMinSignificant());y[0]=ad[0];y[1]=ad[1];if(y.length>2){ad=r(y[1],y[2],u.getRandomRoundMinSignificant());y[1]=ad[0];y[2]=ad[1]}}var af=true;for(var A in y){var ae=y[A];if(ae.compareTo(BigInteger.valueOf(u.getMinimumInputValue()))<0||ae.compareTo(BigInteger.valueOf(u.getMaximumOutputValue()))>0){af=false;break}}if(af){O=y;break}}for(var A in O){var I=O[A];var J=V.generateAddressFromSeed();z.request_outputs.push({value:I.toString(),script:Crypto.util.bytesToHex(Script.createOutputScript(J).buffer)})}if(ac.compareTo(BigInteger.ZERO)>0){var K=V.generateChangeAddress();if(ac.compareTo(BigInteger.valueOf(u.getMinimumOutputValueExcludingFee()))<0){throw"Change Value Too Small 0 ("+ac.toString()+" < "+u.getMinimumOutputValueExcludingFee()+")"}z.request_outputs.push({value:ac.toString(),script:Crypto.util.bytesToHex(Script.createOutputScript(K).buffer),exclude_from_fee:true})}V.offers.push(z);Q=z}for(var A in Q.request_outputs){var B=Q.request_outputs[A];if(!B.exclude_from_fee){H.offered_outpoints.push(B)}}if(S.compareTo(BigInteger.ZERO)>0){var K=V.generateChangeAddress();if(S.compareTo(BigInteger.valueOf(u.getMinimumOutputValueExcludingFee()))<0){throw"Change Value Too Small 1 ("+S.toString()+" < "+u.getMinimumOutputValueExcludingFee()+")"}H.request_outputs.push({value:S.toString(),script:Crypto.util.bytesToHex(Script.createOutputScript(K).buffer),exclude_from_fee:true})}V.offers.push(H);M(V)}catch(ab){X(ab)}}}};this.getRandomRoundMinSignificant=function(){return a.random_round_min_significant};this.getMaxOutputSplits=function(){return a.max_output_splits};this.getMinOutputSplits=function(){return a.min_output_splits};this.getMaxTotalFeePayingOutputValue=function(){return a.max_total_fee_paying_output_value};this.getMaximumOfferNumberOfInputs=function(){return a.maximum_offer_number_of_inputs};this.getMaximumOfferNumberOfOutputs=function(){return a.maximum_offer_number_of_outputs};this.getMinimumOutputValue=function(){return a.minimum_output_value};this.getMinimumOutputValueExcludingFee=function(){return a.minimum_output_value_exclude_fee};this.getToken=function(){return a.token};this.getMinimumInputValue=function(){return a.minimum_input_value};this.getMaximumInputValue=function(){return a.maximum_input_value};this.getMinimumSupportedVersion=function(){return a.min_supported_version};this.getIsEnabled=function(){return a.enabled};this.getMaximumOutputValue=function(){return a.maximum_output_value};this.getFee=function(){return a.fee_percent};this.getMinimumFee=function(){return a.minimum_fee?a.minimum_fee:0};this.getMinRecommendedIterations=function(){return a.recommended_min_iterations};this.getMaxRecommendedIterations=function(){return a.recommended_max_iterations};this.getMinRecommendedWaitTime=function(){return a.recommended_min_wait_time};this.getMaxRecommendedWaitTime=function(){return a.recommended_max_wait_time};this.constructPlan=function(B,L,X){try{var S=this;var H=B.find('select[name="privacy-required"]');var A=B.find('input[name="shared-coin-donate"]').is(":checked");var P=H.val();if(P=="normal"){var N=u.getMinRecommendedIterations()+(Math.random()<0.5?-1:1);var F=u.getMinRecommendedWaitTime();var E=2}else{if(P=="higher"){var N=u.getMaxRecommendedIterations()+(Math.random()<0.5?-1:1);var F=u.getMaxRecommendedWaitTime();var E=3}else{throw"Unknown privacy setting. Try refreshing the page?"}}F+=Math.round(F*((Math.random()*0.5)-0.25));if(N<=0||isNaN(N)){throw"Invalid number of repetitions"}if(F<=0||isNaN(F)){throw"Invalid waitTime"}if(E<0||isNaN(E)){throw"Invalid Number Of Target Change Addresses"}console.log("constructPlan() Number Of Repetitions "+N+" Donate "+A+" privacyRequired "+P+" waitTime "+F+" targetNumberOfChangeAddresses "+E);var C=u.newPlan();function I(ag){for(var af in C.generated_addresses){MyWallet.deleteAddress(C.generated_addresses[af])}X(ag)}var aa=initNewTx();aa.from_addresses=MyWallet.getActiveAddresses();var M=B.find(".recipient");if(M.length>u.getMaximumOfferNumberOfOutputs()){throw"The Maximum Number Of Recipients is "+u.getMaximumOfferNumberOfOutputs()}var R={};M.each(function(){try{var am=$(this);var ak=am.find('input[name="send-value"]');var ah=am.find('input[name="send-to-address"]');var ai=0;try{ai=precisionToSatoshiBN(ak.val());if(ai==null||ai.compareTo(BigInteger.ZERO)<=0){throw"You must enter a value greater than zero"}}catch(aj){throw"Invalid send amount"}if(ai.compareTo(BigInteger.valueOf(u.getMinimumOutputValue()))<0){throw"Output Value Too Small"}var af=$.trim(ah.val()).replace(/[\u200B-\u200D\uFEFF]/g,"");if(af==null||af.length==0){throw"You must enter a bitcoin address for each recipient"}var ag=resolveAddress(af);if(ag==null||ag.length==0){throw"You must enter a bitcoin address for each recipient"}if(R[ag]){throw"Shared Coin does not support multiple outputs to the same recipient"}R[ag]=true;var al=new Bitcoin.Address(ag);if(al.version!=0){throw"Shared Coin only supports sending payments to regular bitcoin addresses"}aa.to_addresses.push({address:al,value:ai});C.to_addresses[ag]=ai}catch(aj){I(aj)}});if(aa.to_addresses.length==0||aa.to_addresses.length<M.length){return}var y=[];var J=[];var Z=[];var V=[];if(A){var ad=(Math.random()*(x-w))+w;var U=(ad/2)*((Math.random()*1.8)+0.2);V.push((U).toFixed(2));V.push((ad-U).toFixed(2))}for(var Y=N-1;Y>=0;--Y){var K=u.getFee();if(V.length>0){K+=V.pop()}Z[Y]=K;J[Y]=BigInteger.ZERO}var ac=BigInteger.ZERO;for(var Y in aa.to_addresses){var ae=aa.to_addresses[Y];y.push(ae.value);for(var Q=N-1;Q>=0;--Q){var T=u.calculateFeeForValue(Z[Q],ae.value);ac=ac.add(T);J[Q]=J[Q].add(T)}}var G=BigInteger.valueOf(u.getMinimumFee());ac=ac.add(G.multiply(BigInteger.valueOf(N)));aa.to_addresses[0].value=aa.to_addresses[0].value.add(ac);for(var Y in J){J[Y]=J[Y].add(G)}var O="1BitcoinEaterAddressDontSendf59kuE";aa.min_input_confirmations=1;aa.do_not_use_unspent_cache=true;aa.allow_adjust=false;aa.change_address=new Bitcoin.Address(O);aa.base_fee=BigInteger.ZERO;aa.min_input_size=BigInteger.valueOf(u.getMinimumInputValue());aa.fee=BigInteger.ZERO;aa.ask_for_fee=function(ag,af){af()};function D(af){var aj={};var ai={};for(var ah in af){var ag=af[ah];var ak=new Bitcoin.Address(ag.script.simpleOutPubKeyHash()).toString();aj[ak]=true;ai[ag.outpoint.hash]=true}return Math.min(p(aj),p(ai))}var W=BigInteger.valueOf(satoshi);aa.sortOutputs=function(af){af=af.sort(function(ah,ag){return ag.value.compareTo(ah.value)});return af};aa.isSelectedValueSufficient=function(ah,ai,af){if(!af){throw"isSelectedValueSufficient inputs null. Please clear your cache and refresh the page"}var ag=this;if(ag.selected_outputs.length>=u.getMaximumOfferNumberOfInputs()){return true}if(ai.compareTo(ah.add(W))>=0&&D(af)>1){return true}return false};var z=u.newOffer();aa.addListener({on_error:function(af){I()}});aa.signInputs=function(){try{var aq=this;if(aq.tx.ins.length>u.getMaximumOfferNumberOfInputs()){I("Maximum number of inputs exceeded. Please consolidate some or lower the send amount");return}for(var ai=0;ai<aq.tx.ins.length;++ai){var ao=aq.tx.ins[ai];var ag=ao.outpoint.hash;var an=Crypto.util.bytesToHex(Crypto.util.base64ToBytes(ag).reverse());z.offered_outpoints.push({hash:an,index:ao.outpoint.index,value:ao.outpoint.value.toString()})}var aj=BigInteger.ZERO;for(var ai=0;ai<aq.tx.outs.length;++ai){var ah=aq.tx.outs[ai];var am=ah.value.slice(0);am.reverse();var ap=new BigInteger(am);var af=new Bitcoin.Script(ah.script).simpleOutPubKeyHash();var al=new Bitcoin.Address(af).toString();if(al.toString()==O){aj=aj.add(ap)}else{z.request_outputs.push({value:y[ai].toString(),script:Crypto.util.bytesToHex(ah.script.buffer)})}}if(aj.compareTo(BigInteger.ZERO)==0){throw"Transaction does not have any change. Shared Coin cannot send the exact amount available in the wallet."}C.fee_each_repetition=J;C.fee_percent_each_repetition=Z;C.constructOffers(z,aj,N,F,E,L,function(ar){I(ar)})}catch(ak){I(ak)}};aa.start()}catch(ab){I(ab)}};this.calculateFeeForValue=function(B,z){if(z.compareTo(BigInteger.ZERO)>0&&B>0){var A=Math.ceil(100/B);var y=z.divide(BigInteger.valueOf(A));return y}else{return BigInteger.ZERO}};this.recoverSeeds=function(B,C,E){MyWallet.disableLogout(true);var F=$("#sharedcoin-recover-progress-modal");var y=F.find(".bar");F.modal("show");y.width("0%");var A=function(I){F.modal("hide");E(I)};var H=function(I){F.modal("hide");C(I)};var z=0;var G=0;function D(){if(!F.is(":visible")){return}if(z>=B.length){if(G>0){MyWallet.get_history();MyWallet.makeNotice("success","misc-success",formatBTC(G)+" recovered from intermediate addresses")}H();return}y.width(((z/B.length)*100)+"%");var K=B[z];++z;var M={};for(var L=0;L<100;++L){var J=u.generateAddressAndKeyFromCustomSeed(K,L);var I=J.address.toString();if(!MyWallet.addressExists(I)){M[I]=J.key}}BlockchainAPI.get_balances(Object.keys(M),function(Q){try{var R=0;for(var O in Q){var S=Q[O].final_balance;if(S>0){console.log("Balance "+O+" = "+S);var N=M[O];var P=N.getBitcoinAddress().toString();try{if(MyWallet.addPrivateKey(N,{compressed:O!=P,app_name:IMPORTED_APP_NAME,app_version:IMPORTED_APP_VERSION})){console.log("Imported "+O)}}catch(T){console.log("Error importing "+O)}}R+=S}if(R>0){G+=R;MyWallet.backupWalletDelayed("update",function(){setTimeout(D,500)})}else{setTimeout(D,500)}}catch(T){A(T)}},A)}setTimeout(D,100)};this.init=function(B,z){if(!MyWallet.getSharedcoinEndpoint()||MyWallet.getSharedcoinEndpoint().length==0){(function(F,H,G){if(!H.is(":visible")){return}if(G>10){return}++G;setTimeout(function(){F.init(H)},2000)})(this,B,z);return}g=MyWallet.getSharedcoinEndpoint()+"?version="+c;$("#sharedcoin-recover").unbind().click(function(){var F=$(this);MyWallet.getSecondPassword(function(){F.prop("disabled",true);var J=F.text();F.text("Working. Please Wait...");var K=MyWallet.getAdditionalSeeds();var G=[];for(var I in K){var H=K[I];if(H.indexOf(i)==0||H.indexOf(e)==0){G.push(H)}}G.reverse();u.recoverSeeds(G,function(){F.prop("disabled",false);F.text(J)},function(L){F.prop("disabled",false);F.text(J);MyWallet.makeNotice("error","misc-error",L)})})});var E=B.find(".send");var C=B.find(".send-options");E.unbind().prop("disabled",true);B.find('input[name="send-value"]').bind("keyup change",function(){y()});C.hide();function D(){var F=C.find("span");F.eq(0).text(formatBTC(u.getMaximumOutputValue()));F.eq(1).text(formatBTC(u.getMinimumOutputValue()));C.show()}function A(){var F=BigInteger.ZERO;B.find('input[name="send-value"]').each(function(){F=F.add(precisionToSatoshiBN($(this).val()))});return F}function y(){E.unbind();if(u.getIsEnabled()&&c>=u.getMinimumSupportedVersion()){var F=A();if(F.compareTo(BigInteger.valueOf(u.getMinimumOutputValue()))<0){E.prop("disabled",true)}else{if(F.compareTo(BigInteger.valueOf(u.getMaximumOutputValue()))>0){E.prop("disabled",true)}else{E.prop("disabled",false);E.unbind().click(function(){var I;if(I){clearInterval(I);I=null}MyWallet.disableLogout(true);var G=function(K,J){console.log("Fatal Error");v.setProgressError();v.setEstimatedTime(0);if(I){clearInterval(I);I=null}B.find("input,select,button").prop("disabled",false);y();MyWallet.disableLogout(false);MyWallet.makeNotice("error","misc-error",K,(J&&J.c_stage)>0?60000:10000);setTimeout(function(){if(J&&J.c_stage>=0){console.log("Recover Seeds");v.hide();u.recoverSeeds([i+J.address_seed],function(){v.show()},function(){v.show()})}},1000);v.enableCancel()};var H=function(){v.setProgressSuccess();v.setEstimatedTime(0);if(I){clearInterval(I);I=null}B.find("input,select,button").prop("disabled",false);MyWallet.makeNotice("success","misc-success","Shared Coin Transaction Successfully Completed");MyWallet.disableLogout(false);v.hide();y()};if(F.compareTo(BigInteger.valueOf(u.getMinimumOutputValue()))<0){MyWallet.makeNotice("error","misc-error","The Minimum Send Value is "+formatPrecision(u.getMinimumOutputValue()));return}else{if(F.compareTo(BigInteger.valueOf(u.getMaximumOutputValue()))>0){MyWallet.makeNotice("error","misc-error","The Maximum Send Value is "+formatPrecision(u.getMaximumOutputValue()));return}}MyWallet.getSecondPassword(function(){loadScript("wallet/signer",function(){v.show();v.setProgressInfo();v.disableCancel();v.setProgress(0,1);v.setEstimatedTime(0);var M=A();var K=B.find(".recipient");if(K.length==1){var N=K.find('input[name="send-to-address"]').val()}else{var N="Multiple Recipients"}v.setAddressAndAmount(N,M);B.find("input,select,button").prop("disabled",true);MyWallet.setLoadingText("Constructing Plan. Please Wait.");var J=new Date().getTime()-o;var L=Math.max(0,f-J);if(L>0){$(".loading-indicator").fadeIn(200)}setTimeout(function(){$(".loading-indicator").hide();u.constructPlan(B,function(O){console.log("Created Plan");I=setInterval(function(){v.setEstimatedTime(O.getEstimatedTimeLeft())},500);O.sanityCheck(function(){console.log("Sanity Check OK");v.hide();k.show(O,function(){v.show();O.execute(H,function(P){G(P,O)},function(P,Q){v.setProgress(P,Q)})},function(){v.show();G()})},G)},G)},L)},G)},G)})}}}else{E.prop("disabled",true)}}MyWallet.setLoadingText("Fetching Shared Coin Info");$.retryAjax({dataType:"json",type:"POST",url:g,timeout:h,retryLimit:d,data:{method:"get_info",format:"json"},success:function(G){try{a=G;if(!u.getIsEnabled()){throw"Shared Coin is currently disabled"}if(c<u.getMinimumSupportedVersion()){throw"Version out of date. Please update your client or reload the page."}D()}catch(F){MyWallet.makeNotice("error","misc-error",F)}y()},error:function(F){E.prop("disabled",true);MyWallet.makeNotice("error","misc-error",F.responseText)}});y()}};