1 line
11 KiB
JavaScript
1 line
11 KiB
JavaScript
(function(e){function t(){return new Promise((e,t)=>{fetch("https://api.blockchain.info/mempool/fees").then(n=>{n.ok?n.json().then(t=>e(parseFloat((t.regular/m).toFixed(8)))).catch(e=>t(e)):t(n)}).catch(e=>t(e))})}function n(e){var t=coinjs.base58decode(e),n=t.slice(0,t.length-4),s=t.slice(t.length-4),r=Crypto.SHA256(Crypto.SHA256(n,{asBytes:!0}),{asBytes:!0});if(r[0]!=s[0]||r[1]!=s[1]||r[2]!=s[2]||r[3]!=s[3])return null;let i=n.shift();return{version:i,hex:Crypto.util.bytesToHex(n)}}function s(e,t){var n=Crypto.util.hexToBytes(e);n.unshift(t);var s=Crypto.SHA256(Crypto.SHA256(n,{asBytes:!0}),{asBytes:!0}),r=s.slice(0,4);return coinjs.base58encode(n.concat(r))}function r(e){let t=coinjs.bech32_decode(e);if(!t)return null;var n=t.data;let s=n.shift();return n=coinjs.bech32_convert(n,5,8,!1),{hrp:t.hrp,version:s,hex:Crypto.util.bytesToHex(n)}}function i(e,t,n){var s=Crypto.util.hexToBytes(e);return s=coinjs.bech32_convert(s,8,5,!0),s.unshift(t),coinjs.bech32_encode(n,s)}function o(e,t){let n=coinjs.addressDecode(e);switch(n.type){case"standard":return!1;case"multisig":return t?coinjs.segwitAddress(y.pubkey(t)).redeemscript:null;case"bech32":return n.redeemscript;default:return null}}function c(e,t){switch(coinjs.addressDecode(e).type){case"standard":return _+k;case"bech32":return _+A;case"multisig":switch(coinjs.script().decodeRedeemScript(t).type){case"segwit__":return _+T;case"multisig__":return _+C;default:return null}default:return null}}function a(e){switch(coinjs.addressDecode(e).type){case"standard":return B+F;case"bech32":return B+P;case"multisig":return B+S;default:return null}}function u(e){let t=[];if(e.senders&&(Array.isArray(e.senders)||(e.senders=[e.senders]),e.senders.forEach(e=>x(e)?null:t.push(e)),t.length))throw"Invalid senders:"+t;if(e.privkeys){if(Array.isArray(e.privkeys)||(e.privkeys=[e.privkeys]),e.senders.length!=e.privkeys.length)throw"Array length for senders and privkeys should be equal";if(e.senders.forEach((n,s)=>{let r=e.privkeys[s];w(n,r)||t.push(n),64===r.length&&(e.privkeys[s]=coinjs.privkey2wif(r))}),t.length)throw"Invalid keys:"+t}if(Array.isArray(e.receivers)||(e.receivers=[e.receivers]),e.receivers.forEach(e=>x(e)?null:t.push(e)),t.length)throw"Invalid receivers:"+t;if(e.change_addr&&!x(e.change_addr))throw"Invalid change_address:"+e.change_addr;if(("number"!=typeof e.fee||e.fee<=0)&&null!==e.fee)throw"Invalid fee:"+e.fee;if(Array.isArray(e.amounts)||(e.amounts=[e.amounts]),e.receivers.length!=e.amounts.length)throw"Array length for receivers and amounts should be equal";if(e.amounts.forEach(e=>"number"!=typeof e||e<=0?t.push(e):null),t.length)throw"Invalid amounts:"+t;return e}function l(e,t,n,s,r,i){return new Promise((o,c)=>{let a=parseFloat(s.reduce((e,t)=>e+t,0).toFixed(8));const u=coinjs.transaction();let l=p(u,n,s,i);d(u,e,t,a,r,l).then(e=>{e.change_amount>0?u.outs[u.outs.length-1].value=parseInt(e.change_amount*m):u.outs.pop(),e.output_size=l,e.output_amount=a,e.total_size=j+l+e.input_size,e.transaction=u,o(e)}).catch(e=>c(e))})}function d(e,n,s,r,i,o){return new Promise((c,a)=>{null!==i?h(e,n,s,r+i,!1).then(e=>{e.fee=i,c(e)}).catch(e=>a(e)):t().then(t=>{let i=j*t;i+=o*t,h(e,n,s,r+i,t).then(e=>{e.fee=parseFloat((i+e.input_size*t).toFixed(8)),e.fee_rate=t,c(e)}).catch(e=>a(e))}).catch(e=>a(e))})}function h(e,t,n,s,r,i={}){return new Promise((o,a)=>{if(s=parseFloat(s.toFixed(8)),void 0===i.n&&(i.n=0,i.input_size=0,i.input_amount=0),s<=0)return o({input_size:i.input_size,input_amount:i.input_amount,change_amount:-1*s});if(i.n>=t.length)return a("Insufficient Balance");let u=t[i.n],l=n[i.n],d=c(u,l);b(`get_tx_unspent/BTC/${u}`).then(c=>{let p=c.data.txs;console.debug("add-utxo",u,l,s,p);for(let t=0;t<p.length&&s>0;t++)if(p[t].confirmations){var f;if(l&&l.length)if(l.match(/^00/)&&44==l.length||40==l.length&&l.match(/^[a-f0-9]+$/gi)){let e=coinjs.script();e.writeBytes(Crypto.util.hexToBytes(l)),e.writeOp(0),e.writeBytes(coinjs.numToBytes((p[t].value*m).toFixed(0),8)),f=Crypto.util.bytesToHex(e.buffer)}else f=l;else f=p[t].script_hex;e.addinput(p[t].txid,p[t].output_no,f,4294967293),i.input_size+=d,i.input_amount+=parseFloat(p[t].value),s-=parseFloat(p[t].value),r&&(s+=d*r)}i.n+=1,h(e,t,n,s,r,i).then(e=>o(e)).catch(e=>a(e))}).catch(e=>a(e))})}function p(e,t,n,s){let r=0;for(let s in t)e.addoutput(t[s],n[s]),r+=a(t[s]);return e.addoutput(s,0),r+=a(s),r}function f(e){if("string"==typeof e||Array.isArray(e))try{e=coinjs.transaction().deserialize(e)}catch{throw"Invalid transaction hex"}else if("object"!=typeof e||"function"!=typeof e.sign)throw"Invalid transaction object";return e}const y=e,g="https://chain.so/api/v2/",b=y.fetch=function(e){return new Promise((t,n)=>{console.debug(g+e),fetch(g+e).then(e=>{e.json().then(e=>"success"===e.status?t(e):n(e)).catch(e=>n(e))}).catch(e=>n(e))})},m=1e8,v=y.broadcastTx=(e=>new Promise((t,n)=>{let s="https://coinb.in/api/?uid=1&key=12345678901234567890123456789012&setmodule=bitcoin&request=sendrawtransaction";fetch(s,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"rawtx="+e}).then(e=>{e.text().then(e=>{let s=e.match(/<result>.*<\/result>/);if(s)if(s=s.pop().replace("<result>","").replace("</result>",""),"1"==s){let n=e.match(/<txid>.*<\/txid>/).pop().replace("<txid>","").replace("</txid>","");t(n)}else if("0"==s){let t=e.match(/<response>.*<\/response>/).pop().replace("<response>","").replace("</response>","");n(decodeURIComponent(t.replace(/\+/g," ")))}else n(e);else n(e)}).catch(e=>n(e))}).catch(e=>n(e))}));Object.defineProperties(y,{newKeys:{get:()=>{let e=coinjs.newKeys();return e.segwitAddress=coinjs.segwitAddress(e.pubkey).address,e.bech32Address=coinjs.bech32Address(e.pubkey).address,e}},pubkey:{value:e=>e.length>=66?e:64==e.length?coinjs.newPubkey(e):coinjs.wif2pubkey(e).pubkey},address:{value:(e,t)=>coinjs.pubkey2address(y.pubkey(e),t)},segwitAddress:{value:e=>coinjs.segwitAddress(y.pubkey(e)).address},bech32Address:{value:e=>coinjs.bech32Address(y.pubkey(e)).address}}),coinjs.compressed=!0;const w=y.verifyKey=function(e,t){if(e&&t)switch(coinjs.addressDecode(e).type){case"standard":return y.address(t)===e;case"multisig":return y.segwitAddress(t)===e;case"bech32":return y.bech32Address(t)===e;default:return null}},x=y.validateAddress=function(e){if(!e)return;let t=coinjs.addressDecode(e).type;return!!["standard","multisig","bech32"].includes(t)&&t};y.multiSigAddress=function(e,t){if(!Array.isArray(e))throw"pubKeys must be an array of public keys";if(e.length<t)throw"minimum required should be less than the number of pubKeys";return coinjs.pubkeys2MultisigAddress(e,t)},y.convert={},y.convert.wif=function(e,t=coinjs.priv){let r=n(e).hex;return!r||r.length<66||!/01$/.test(r)?null:s(r,t)},y.convert.legacy2legacy=function(e,t=coinjs.pub){let r=n(e).hex;return r?s(r,t):null},y.convert.legacy2bech=function(e,t=coinjs.bech32.version,s=coinjs.bech32.hrp){let r=n(e).hex;return r?i(r,t,s):null},y.convert.bech2bech=function(e,t=coinjs.bech32.version,n=coinjs.bech32.hrp){let s=r(e).hex;return s?i(s,t,n):null},y.convert.bech2legacy=function(e,t=coinjs.pub){let n=r(e).hex;return n?s(n,t):null},y.getBalance=(e=>new Promise((t,n)=>{b(`get_address_balance/BTC/${e}`).then(e=>t(parseFloat(e.data.confirmed_balance))).catch(e=>n(e))}));const j=12,_=41,k=107,A=27,T=59,C=351,B=9,F=25,P=23,S=23;y.sendTx=function(e,t,n,s,r,i=null){return new Promise((o,c)=>{z(e,t,n,s,r,i).then(e=>{v(e.transaction.serialize()).then(e=>o(e)).catch(e=>c(e))}).catch(e=>c(e))})};const z=y.createSignedTx=function(e,t,n,s,r=null,i=null){return new Promise((c,a)=>{try{({senders:e,privkeys:t,receivers:n,amounts:s}=u({senders:e,privkeys:t,receivers:n,amounts:s,fee:r,change_addr:i}))}catch(e){return a(e)}let d=[],h=[];for(let n in e){let s=o(e[n],t[n]);d.push(s),!1===s?h.unshift(t[n]):h.push(t[n])}if(d.includes(null))return a("Unable to get redeem-script");l(e,d,n,s,r,i||e[0]).then(e=>{let t=e.transaction;console.debug("Unsigned:",t.serialize()),new Set(h).forEach(e=>console.debug("Signing key:",e,t.sign(e,1))),console.debug("Signed:",t.serialize()),c(e)}).catch(e=>a(e))})};y.createTx=function(e,t,n,s=null,r=null){return new Promise((i,c)=>{try{({senders:e,receivers:t,amounts:n}=u({senders:e,receivers:t,amounts:n,fee:s,change_addr:r}))}catch(e){return c(e)}let a=e.map(e=>o(e));if(a.includes(null))return c("Unable to get redeem-script");l(e,a,t,n,s,r||e[0]).then(e=>{e.tx_hex=e.transaction.serialize(),delete e.transaction,i(e)}).catch(e=>c(e))})},y.createMultiSigTx=function(e,t,n,s,r=null){return new Promise((i,o)=>{if("multisig"!==x(e))return o("Invalid sender (multisig):"+e);{let n=coinjs.script(),s=n.decodeRedeemScript(t);if(!s||s.address!==e)return o("Invalid redeem-script")}try{({receivers:n,amounts:s}=u({receivers:n,amounts:s,fee:r}))}catch(e){return o(e)}l([e],[t],n,s,r,e).then(e=>{e.tx_hex=e.transaction.serialize(),delete e.transaction,i(e)}).catch(e=>o(e))})},y.signTx=function(e,t,n=1){e=f(e),Array.isArray(t)||(t=[t]);for(let e in t)64===t[e].length&&(t[e]=coinjs.privkey2wif(t[e]));return new Set(t).forEach(t=>e.sign(t,n)),e.serialize()};const H=y.checkSigned=function(e,t=!0){e=f(e);let n=[];for(let t in e.ins){var s=e.extractScriptKey(t);if("multisig"!==s.type)n.push("true"==s.signed||e.witness[t]&&2==e.witness[t].length);else{var r=coinjs.script().decodeRedeemScript(s.script);let e={s:s.signatures,r:r.signaturesRequired,t:r.pubkeys.length};if(e.r>e.t)throw"signaturesRequired is more than publicKeys";e.s<e.r?n.push(e):n.push(!0)}}return t?!n.filter(e=>!0!==e).length:n};y.checkIfSameTx=function(e,t){if(e=f(e),t=f(t),e.ins.length!==t.ins.length||e.outs.length!==t.outs.length)return!1;for(let n=0;n<e.ins.length;n++)if(e.ins[n].outpoint.hash!==t.ins[n].outpoint.hash||e.ins[n].outpoint.index!==t.ins[n].outpoint.index)return!1;for(let n=0;n<t.ins.length;n++)if(e.outs[n].value!==t.outs[n].value||Crypto.util.bytesToHex(e.outs[n].script.buffer)!==Crypto.util.bytesToHex(t.outs[n].script.buffer))return!1;return!0};const I=(e,t)=>new Promise((n,s)=>{b(`get_tx_outputs/BTC/${e}/${t}`).then(e=>n(e.data.outputs)).catch(e=>s(e))});y.parseTransaction=function(e){return new Promise((t,n)=>{e=f(e);let r={},o=[];for(let t=0;t<e.ins.length;t++)o.push(I(e.ins[t].outpoint.hash,e.ins[t].outpoint.index));Promise.all(o).then(n=>{r.inputs=n.map(e=>Object({address:e.address,value:parseFloat(e.value)}));let o=H(e,!1);r.inputs.forEach((e,t)=>e.signed=o[t]),r.outputs=e.outs.map(e=>{var t;switch(e.script.chunks[0]){case 0:t=i(Crypto.util.bytesToHex(e.script.chunks[1]),coinjs.bech32.version,coinjs.bech32.hrp);break;case 169:t=s(Crypto.util.bytesToHex(e.script.chunks[1]),coinjs.multisig);break;case 118:t=s(Crypto.util.bytesToHex(e.script.chunks[2]),coinjs.pub)}return{address:t,value:parseFloat(e.value/m)}}),r.total_input=parseFloat(r.inputs.reduce((e,t)=>e+=t.value,0).toFixed(8)),r.total_output=parseFloat(r.outputs.reduce((e,t)=>e+=t.value,0).toFixed(8)),r.fee=parseFloat((r.total_input-r.total_output).toFixed(8)),t(r)}).catch(e=>n(e))})},y.transactionID=function(e){e=f(e);let t=coinjs.clone(e);t.witness=null;let n=Crypto.util.hexToBytes(t.serialize()),s=Crypto.SHA256(Crypto.SHA256(n,{asBytes:!0}),{asBytes:!0}).reverse();return Crypto.util.bytesToHex(s)},y.getTx=(e=>new Promise((t,n)=>{b(`tx/BTC/${e}`).then(e=>t(e.data)).catch(e=>n(e))})),y.getAddressData=(e=>new Promise((t,n)=>{b(`address/BTC/${e}`).then(e=>t(e.data)).catch(e=>n(e))})),y.getBlock=(e=>new Promise((t,n)=>{b(`get_block/BTC/${e}`).then(e=>t(e.data)).catch(e=>n(e))}))})("object"==typeof module?module.exports:window.btcOperator={}); |