mostly support lbry
it cannot sign timelocked txns because the private key is for the underlying address, so it doesn't know which inputs to sign also broadcasting doesnt work yet because there's no broadcast endpoint on chainquery
This commit is contained in:
parent
cda4559cfd
commit
f0ace3eae5
3 changed files with 116 additions and 336 deletions
|
@ -1382,13 +1382,7 @@
|
||||||
<b>Network</b>: <br>
|
<b>Network</b>: <br>
|
||||||
<p class="text-muted">Select which network you'd like to use for key pair generation.</p>
|
<p class="text-muted">Select which network you'd like to use for key pair generation.</p>
|
||||||
<select class="form-control" id="coinjs_coin">
|
<select class="form-control" id="coinjs_coin">
|
||||||
<option value="bitcoin_mainnet" rel="0x00;0x80;0x05;0x488b21e;0x488ade4;coinb.in;coinb.in">Bitcoin (mainnet)</option>
|
<option value="custom" rel="0x55;0x1c;0x7a;0x488b21e;0x488ade4;false;false">Custom</option>
|
||||||
<option value="litecoin_mainnet" rel="0x30;0xb0;0x32;0x019da462;0x019d9cfe;blockcypher_litecoin;blockcypher_litecoin">Litecoin (mainnet)</option>
|
|
||||||
<option value="dogecoin_mainnet" rel="0x1e;0x9e;0x16;0x0827421e;0x089944e4;blockcypher_dogecoin;blockcypher_dogecoin">Dogecoin (mainnet)</option>
|
|
||||||
<option value="shadowcash_mainnet" rel="0x3f;0xbf;0x7d;0xee80286a;0xee8031e8;false;false">ShadowCash (mainnet)</option>
|
|
||||||
<option value="bitcoin_testnet" rel="0x6f;0xef;0xc4;0x043587cf;0x04358394;false;false">Bitcoin (testnet)</option>
|
|
||||||
|
|
||||||
<option value="custom" rel="0x00;0x80;0x05;0x488b21e;0x488ade4;false;false">Custom</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
93
js/coin.js
93
js/coin.js
|
@ -10,11 +10,11 @@
|
||||||
var coinjs = window.coinjs = function () { };
|
var coinjs = window.coinjs = function () { };
|
||||||
|
|
||||||
/* public vars */
|
/* public vars */
|
||||||
coinjs.pub = 0x00;
|
coinjs.pub = 0x55;
|
||||||
coinjs.priv = 0x80;
|
coinjs.priv = 0x1c;
|
||||||
coinjs.multisig = 0x05;
|
coinjs.multisig = 0x7a;
|
||||||
coinjs.hdkey = {'prv':0x0488ade4, 'pub':0x0488b21e};
|
coinjs.hdkey = {'prv':0x0488ade4, 'pub':0x0488b21e};
|
||||||
coinjs.bech32 = {'charset':'qpzry9x8gf2tvdw0s3jn54khce6mua7l', 'version':0, 'hrp':'bc'};
|
coinjs.bech32 = {'charset':'qpzry9x8gf2tvdw0s3jn54khce6mua7l', 'version':0, 'hrp':'lbc'};
|
||||||
|
|
||||||
coinjs.compressed = false;
|
coinjs.compressed = false;
|
||||||
|
|
||||||
|
@ -22,10 +22,13 @@
|
||||||
coinjs.developer = '33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G'; //bitcoin
|
coinjs.developer = '33tht1bKDgZVxb39MnZsWa8oxHXHvUYE4G'; //bitcoin
|
||||||
|
|
||||||
/* bit(coinb.in) api vars */
|
/* bit(coinb.in) api vars */
|
||||||
coinjs.hostname = ((document.location.hostname.split(".")[(document.location.hostname.split(".")).length-1]) == 'onion') ? 'coinbin3ravkwb24f7rmxx6w3snkjw45jhs5lxbh3yfeg3vpt6janwqd.onion' : 'coinb.in';
|
// coinjs.hostname = ((document.location.hostname.split(".")[(document.location.hostname.split(".")).length-1]) == 'onion') ? 'coinbin3ravkwb24f7rmxx6w3snkjw45jhs5lxbh3yfeg3vpt6janwqd.onion' : 'coinb.in';
|
||||||
|
coinjs.hostname = 'localhost:8000';
|
||||||
coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+coinjs.hostname+'/api/';
|
coinjs.host = ('https:'==document.location.protocol?'https://':'http://')+coinjs.hostname+'/api/';
|
||||||
coinjs.uid = '1';
|
coinjs.uid = '1';
|
||||||
coinjs.key = '12345678901234567890123456789012';
|
coinjs.key = '12345678901234567890123456789012';
|
||||||
|
coinjs.chainqueryAPI = "https://chainquery.lbry.com/api/sql"
|
||||||
|
|
||||||
|
|
||||||
/* start of address functions */
|
/* start of address functions */
|
||||||
|
|
||||||
|
@ -177,6 +180,37 @@
|
||||||
return {'address':address, 'redeemScript':redeemScript};
|
return {'address':address, 'redeemScript':redeemScript};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coinjs.timelockedAddress = function(pubkey, checklocktimeverify) {
|
||||||
|
|
||||||
|
if(checklocktimeverify < 0) {
|
||||||
|
throw "Parameter for OP_CHECKLOCKTIMEVERIFY is negative.";
|
||||||
|
}
|
||||||
|
|
||||||
|
var s = coinjs.script();
|
||||||
|
if (checklocktimeverify <= 16 && checklocktimeverify >= 1) {
|
||||||
|
s.writeOp(0x50 + checklocktimeverify);//OP_1 to OP_16 for minimal encoding
|
||||||
|
} else {
|
||||||
|
s.writeBytes(coinjs.numToScriptNumBytes(checklocktimeverify));
|
||||||
|
}
|
||||||
|
s.writeOp(0xb1);//OP_CHECKLOCKTIMEVERIFY
|
||||||
|
s.writeOp(0x75);//OP_DROP
|
||||||
|
s.writeOp(0x76);//OP_DUP
|
||||||
|
s.writeOp(0xa9);//OP_HASH160
|
||||||
|
s.writeBytes(Crypto.util.hexToBytes(pubkey));
|
||||||
|
s.writeOp(0x88);//88 OP_EQUALVERIFY
|
||||||
|
s.writeOp(0xac);//OP_CHECKSIG
|
||||||
|
|
||||||
|
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};
|
||||||
|
}
|
||||||
|
|
||||||
/* create a new segwit address */
|
/* create a new segwit address */
|
||||||
coinjs.segwitAddress = function(pubkey){
|
coinjs.segwitAddress = function(pubkey){
|
||||||
var keyhash = [0x00,0x14].concat(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubkey), {asBytes: true}), {asBytes: true}));
|
var keyhash = [0x00,0x14].concat(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubkey), {asBytes: true}), {asBytes: true}));
|
||||||
|
@ -321,7 +355,8 @@
|
||||||
|
|
||||||
/* retreive the balance from a given address */
|
/* retreive the balance from a given address */
|
||||||
coinjs.addressBalance = function(address, callback){
|
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");
|
const query = 'select balance from address where address = "'+address+'";'
|
||||||
|
coinjs.ajax(coinjs.chainqueryAPI+'?query='+encodeURIComponent(query), (response)=>{callback(JSON.parse(response))}, "GET");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decompress an compressed public key */
|
/* decompress an compressed public key */
|
||||||
|
@ -899,6 +934,16 @@
|
||||||
var rs = Crypto.util.bytesToHex(s.buffer);
|
var rs = Crypto.util.bytesToHex(s.buffer);
|
||||||
r.redeemscript = rs;
|
r.redeemscript = rs;
|
||||||
r.type = "hodl__";
|
r.type = "hodl__";
|
||||||
|
|
||||||
|
} else if(s.chunks.length == 8 && s.chunks[1] == 177 && s.chunks[2] == 117 && s.chunks[3] == 118 && s.chunks[7] == 172){
|
||||||
|
// ^ <unlocktime> OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 <pubkey> OP_EQUALVERIFY OP_CHECKSIG ^
|
||||||
|
r = {}
|
||||||
|
r.pubkey = Crypto.util.bytesToHex(s.chunks[5]);
|
||||||
|
r.checklocktimeverify = coinjs.bytesToNum(s.chunks[0].slice());
|
||||||
|
r.address = coinjs.timelockedAddress(r.pubkey, r.checklocktimeverify).address;
|
||||||
|
var rs = Crypto.util.bytesToHex(s.buffer);
|
||||||
|
r.redeemscript = rs;
|
||||||
|
r.type = "hodl__";
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// console.log(e);
|
// console.log(e);
|
||||||
|
@ -1064,12 +1109,14 @@
|
||||||
|
|
||||||
/* list unspent transactions */
|
/* list unspent transactions */
|
||||||
r.listUnspent = function(address, callback) {
|
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");
|
const query = 'select o.transaction_hash, o.vout, o.value, o.script_pub_key_hex, o.type from address a inner join transaction_address ta on a.id = ta.address_id inner join output o on o.transaction_id = ta.transaction_id and o.is_spent = 0 and o.type not in ("nonstandard","nulldata") and o.address_list = \'["'+address+'"]\' where a.address = "'+address+'";'
|
||||||
|
coinjs.ajax(coinjs.chainqueryAPI+'?query='+encodeURIComponent(query), (response)=>{callback(JSON.parse(response))}, "GET");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* list transaction data */
|
/* list transaction data */
|
||||||
r.getTransaction = function(txid, callback) {
|
r.getTransaction = function(txid, callback) {
|
||||||
coinjs.ajax(coinjs.host+'?uid='+coinjs.uid+'&key='+coinjs.key+'&setmodule=bitcoin&request=gettransaction&txid='+txid+'&r='+Math.random(), callback, "GET");
|
const query = 'select transaction_hash, vout, value, script_pub_key_hex from output where is_spent = 0 and type not in ("nonstandard","nulldata") and transaction_hash = "'+txid+'"'
|
||||||
|
coinjs.ajax(coinjs.chainqueryAPI+'?query='+encodeURIComponent(query), (response)=>{callback(JSON.parse(response))}, "GET");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add unspent to transaction */
|
/* add unspent to transaction */
|
||||||
|
@ -1081,23 +1128,12 @@
|
||||||
var total = 0;
|
var total = 0;
|
||||||
var x = {};
|
var x = {};
|
||||||
|
|
||||||
if (window.DOMParser) {
|
if(data){
|
||||||
parser=new DOMParser();
|
for(i=0;i<=data["data"].length;i++){
|
||||||
xmlDoc=parser.parseFromString(data,"text/xml");
|
var u = data["data"][i]
|
||||||
} else {
|
var txhash = u["transaction_hash"];
|
||||||
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
|
var n = u["vout"];
|
||||||
xmlDoc.async=false;
|
var scr = script || n["script_pub_key_hex"];
|
||||||
xmlDoc.loadXML(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
var unspent = xmlDoc.getElementsByTagName("unspent")[0];
|
|
||||||
|
|
||||||
if(unspent){
|
|
||||||
for(i=1;i<=unspent.childElementCount;i++){
|
|
||||||
var u = xmlDoc.getElementsByTagName("unspent_"+i)[0]
|
|
||||||
var txhash = (u.getElementsByTagName("tx_hash")[0].childNodes[0].nodeValue).match(/.{1,2}/g).reverse().join("")+'';
|
|
||||||
var n = u.getElementsByTagName("tx_output_n")[0].childNodes[0].nodeValue;
|
|
||||||
var scr = script || u.getElementsByTagName("script")[0].childNodes[0].nodeValue;
|
|
||||||
|
|
||||||
if(segwit){
|
if(segwit){
|
||||||
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
|
/* this is a small hack to include the value with the redeemscript to make the signing procedure smoother.
|
||||||
|
@ -1106,22 +1142,19 @@
|
||||||
s = coinjs.script();
|
s = coinjs.script();
|
||||||
s.writeBytes(Crypto.util.hexToBytes(script));
|
s.writeBytes(Crypto.util.hexToBytes(script));
|
||||||
s.writeOp(0);
|
s.writeOp(0);
|
||||||
s.writeBytes(coinjs.numToBytes(u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1, 8));
|
s.writeBytes(coinjs.numToBytes(u["value"]));
|
||||||
scr = Crypto.util.bytesToHex(s.buffer);
|
scr = Crypto.util.bytesToHex(s.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
var seq = sequence || false;
|
var seq = sequence || false;
|
||||||
self.addinput(txhash, n, scr, seq);
|
self.addinput(txhash, n, scr, seq);
|
||||||
value += u.getElementsByTagName("value")[0].childNodes[0].nodeValue*1;
|
value += u["value"];
|
||||||
total++;
|
total++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x.result = xmlDoc.getElementsByTagName("result")[0].childNodes[0].nodeValue;
|
|
||||||
x.unspent = unspent;
|
|
||||||
x.value = value;
|
x.value = value;
|
||||||
x.total = total;
|
x.total = total;
|
||||||
x.response = xmlDoc.getElementsByTagName("response")[0].childNodes[0].nodeValue;
|
|
||||||
|
|
||||||
return callback(x);
|
return callback(x);
|
||||||
});
|
});
|
||||||
|
|
311
js/coinbin.js
311
js/coinbin.js
|
@ -2,9 +2,9 @@ $(document).ready(function() {
|
||||||
|
|
||||||
/* open wallet code */
|
/* open wallet code */
|
||||||
|
|
||||||
var explorer_tx = "https://coinb.in/tx/"
|
var explorer_tx = "https://explorer.lbry.com/tx/"
|
||||||
var explorer_addr = "https://coinb.in/addr/"
|
var explorer_addr = "https://explorer.lbry.com/address/"
|
||||||
var explorer_block = "https://coinb.in/block/"
|
var explorer_block = "https://explorer.lbry.com/blocks/"
|
||||||
|
|
||||||
var wallet_timer = false;
|
var wallet_timer = false;
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ $(document).ready(function() {
|
||||||
|
|
||||||
tx2.broadcast(function(data){
|
tx2.broadcast(function(data){
|
||||||
if($(data).find("result").text()=="1"){
|
if($(data).find("result").text()=="1"){
|
||||||
$("#walletSendConfirmStatus").removeClass('hidden').addClass('alert-success').html('txid: <a href="https://coinb.in/tx/'+$(data).find("txid").text()+'" target="_blank">'+$(data).find("txid").text()+'</a>');
|
$("#walletSendConfirmStatus").removeClass('hidden').addClass('alert-success').html('txid: <a href="'+explorer_tx+$(data).find("txid").text()+'" target="_blank">'+$(data).find("txid").text()+'</a>');
|
||||||
} else {
|
} else {
|
||||||
$("#walletSendConfirmStatus").removeClass('hidden').addClass('alert-danger').html(unescape($(data).find("response").text()).replace(/\+/g,' '));
|
$("#walletSendConfirmStatus").removeClass('hidden').addClass('alert-danger').html(unescape($(data).find("response").text()).replace(/\+/g,' '));
|
||||||
$("#walletSendFailTransaction").removeClass('hidden');
|
$("#walletSendFailTransaction").removeClass('hidden');
|
||||||
|
@ -302,14 +302,13 @@ $(document).ready(function() {
|
||||||
|
|
||||||
function walletBalance(){
|
function walletBalance(){
|
||||||
if($("#walletLoader").hasClass("hidden")){
|
if($("#walletLoader").hasClass("hidden")){
|
||||||
var tx = coinjs.transaction();
|
|
||||||
$("#walletLoader").removeClass("hidden");
|
$("#walletLoader").removeClass("hidden");
|
||||||
coinjs.addressBalance($("#walletAddress").html(),function(data){
|
coinjs.addressBalance($("#walletAddress").html(),function(data){
|
||||||
if($(data).find("result").text()==1){
|
if(data["success"]){
|
||||||
var v = $(data).find("balance").text()/100000000;
|
const v = data["data"][0]["balance"];
|
||||||
$("#walletBalance").html(v+" BTC").attr('rel',v).fadeOut().fadeIn();
|
$("#walletBalance").html(v+" LBC").attr('rel',v).fadeOut().fadeIn();
|
||||||
} else {
|
} else {
|
||||||
$("#walletBalance").html("0.00 BTC").attr('rel',v).fadeOut().fadeIn();
|
$("#walletBalance").html("0.00 LBC").attr('rel',0).fadeOut().fadeIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#walletLoader").addClass("hidden");
|
$("#walletLoader").addClass("hidden");
|
||||||
|
@ -908,34 +907,7 @@ $(document).ready(function() {
|
||||||
|
|
||||||
var host = $(this).attr('rel');
|
var host = $(this).attr('rel');
|
||||||
|
|
||||||
// api: blockcypher blockchair chain.so
|
|
||||||
// network name "btc" "bitcoin" "BTC"
|
|
||||||
// network name "ltc" "litecoin" "LTC"
|
|
||||||
// network name "doge" "dogecoin" "DOGE"
|
|
||||||
|
|
||||||
if(host=='chain.so_bitcoinmainnet'){
|
|
||||||
listUnspentChainso(redeem, "BTC");
|
|
||||||
} else if(host=='chain.so_litecoin'){
|
|
||||||
listUnspentChainso(redeem, "LTC");
|
|
||||||
} else if(host=='chain.so_dogecoin'){
|
|
||||||
listUnspentChainso(redeem, "DOGE");
|
|
||||||
|
|
||||||
} else if(host=='blockcypher_bitcoinmainnet'){
|
|
||||||
listUnspentBlockcypher(redeem, "btc");
|
|
||||||
} else if(host=='blockcypher_litecoin'){
|
|
||||||
listUnspentBlockcypher(redeem, "ltc");
|
|
||||||
} else if(host=='blockcypher_dogecoin'){
|
|
||||||
listUnspentBlockcypher(redeem, "doge");
|
|
||||||
|
|
||||||
} else if(host=='blockchair_bitcoinmainnet'){
|
|
||||||
listUnspentBlockchair(redeem, "bitcoin");
|
|
||||||
} else if(host=='blockchair_litecoin'){
|
|
||||||
listUnspentBlockchair(redeem, "litecoin");
|
|
||||||
} else if(host=='blockchair_dogecoin'){
|
|
||||||
listUnspentBlockchair(redeem, "dogecoin");
|
|
||||||
} else {
|
|
||||||
listUnspentDefault(redeem);
|
listUnspentDefault(redeem);
|
||||||
}
|
|
||||||
|
|
||||||
if($("#redeemFromStatus").hasClass("hidden")) {
|
if($("#redeemFromStatus").hasClass("hidden")) {
|
||||||
// An ethical dilemma: Should we automatically set nLockTime?
|
// An ethical dilemma: Should we automatically set nLockTime?
|
||||||
|
@ -1001,6 +973,7 @@ $(document).ready(function() {
|
||||||
|
|
||||||
$('#recipients .row[rel="'+redeem.addr+'"]').parent().remove();
|
$('#recipients .row[rel="'+redeem.addr+'"]').parent().remove();
|
||||||
|
|
||||||
|
if (redeem.decodedRs.pubkeys) {
|
||||||
$.each(redeem.decodedRs.pubkeys, function(i, o){
|
$.each(redeem.decodedRs.pubkeys, function(i, o){
|
||||||
$.each($("#mediatorList option"), function(mi, mo){
|
$.each($("#mediatorList option"), function(mi, mo){
|
||||||
|
|
||||||
|
@ -1023,6 +996,7 @@ $(document).ready(function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
validateOutputAmount();
|
validateOutputAmount();
|
||||||
}
|
}
|
||||||
|
@ -1075,18 +1049,21 @@ $(document).ready(function() {
|
||||||
|
|
||||||
if(redeem.from == 'txid'){
|
if(redeem.from == 'txid'){
|
||||||
tx.getTransaction(redeem.addr, function(data){
|
tx.getTransaction(redeem.addr, function(data){
|
||||||
|
if (data["error"]) {
|
||||||
|
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs. '+data["error"]);
|
||||||
|
$("#redeemFromBtn").html("Load").attr('disabled',false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Attempted to rebuild transaction id <a href="'+explorer_tx+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
|
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Attempted to rebuild transaction id <a href="'+explorer_tx+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
|
||||||
|
|
||||||
$.each($(data).find("inputs").children(), function(i,o){
|
$.each(data["data"], function(i,o){
|
||||||
var tx = $(o).find("txid").text();
|
var tx = o["transaction_hash"];
|
||||||
var n = $(o).find("output_no").text();
|
var n = o["vout"];
|
||||||
var amount = (($(o).find("value").text()*1)).toFixed(8);
|
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o["script_pub_key_hex"];
|
||||||
|
var amount = o["value"];
|
||||||
var scr = $(o).find("script").text();
|
|
||||||
|
|
||||||
addOutput(tx, n, scr, amount);
|
|
||||||
|
|
||||||
|
addOutput(tx, n, script, amount);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#recipients .addressRemoveTo").click();
|
$("#recipients .addressRemoveTo").click();
|
||||||
|
@ -1109,14 +1086,20 @@ $(document).ready(function() {
|
||||||
// unspent from address
|
// unspent from address
|
||||||
|
|
||||||
tx.listUnspent(redeem.addr, function(data){
|
tx.listUnspent(redeem.addr, function(data){
|
||||||
|
if (data["error"]) {
|
||||||
|
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs. '+data["error"]);
|
||||||
|
$("#redeemFromBtn").html("Load").attr('disabled',false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(redeem.addr) {
|
if(redeem.addr) {
|
||||||
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
|
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
|
||||||
|
|
||||||
$.each($(data).find("unspent").children(), function(i,o){
|
$.each(data["data"], function(i,o){
|
||||||
var tx = $(o).find("tx_hash").text();
|
var tx = o["transaction_hash"];
|
||||||
var n = $(o).find("tx_output_n").text();
|
var n = o["vout"];
|
||||||
var script = (redeem.redeemscript==true) ? redeem.decodedRs : $(o).find("script").text();
|
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o["script_pub_key_hex"];
|
||||||
var amount = (($(o).find("value").text()*1)/100000000).toFixed(8);
|
var amount = o["value"];
|
||||||
|
|
||||||
addOutput(tx, n, script, amount);
|
addOutput(tx, n, script, amount);
|
||||||
});
|
});
|
||||||
|
@ -1130,107 +1113,6 @@ $(document).ready(function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* retrieve unspent data from blockcypher */
|
|
||||||
function listUnspentBlockcypher(redeem,network){
|
|
||||||
$.ajax ({
|
|
||||||
type: "GET",
|
|
||||||
url: "https://api.blockcypher.com/v1/"+network+"/main/addrs/"+redeem.addr+"?includeScript=true&unspentOnly=true",
|
|
||||||
dataType: "json",
|
|
||||||
error: function(data) {
|
|
||||||
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
if (data.address) { // address field will always be present, txrefs is only present if there are UTXOs
|
|
||||||
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
|
|
||||||
for(var i in data.txrefs){
|
|
||||||
var o = data.txrefs[i];
|
|
||||||
var tx = ((""+o.tx_hash).match(/.{1,2}/g).reverse()).join("")+'';
|
|
||||||
if(tx.match(/^[a-f0-9]+$/)){
|
|
||||||
var n = o.tx_output_n;
|
|
||||||
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o.script;
|
|
||||||
var amount = ((o.value.toString()*1)/100000000).toFixed(8);
|
|
||||||
addOutput(tx, n, script, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function(data, status) {
|
|
||||||
$("#redeemFromBtn").html("Load").attr('disabled',false);
|
|
||||||
totalInputAmount();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* retrieve unspent data from blockchair */
|
|
||||||
function listUnspentBlockchair(redeem,network){
|
|
||||||
$.ajax ({
|
|
||||||
type: "GET",
|
|
||||||
url: "https://api.blockchair.com/"+network+"/dashboards/address/"+redeem.addr,
|
|
||||||
dataType: "json",
|
|
||||||
error: function(data) {
|
|
||||||
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
if((data.context && data.data) && data.context.code =='200'){
|
|
||||||
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
|
|
||||||
var all_info = data.data[redeem.addr];
|
|
||||||
for(var i in all_info.utxo){
|
|
||||||
var o = all_info.utxo[i];
|
|
||||||
var tx = ((""+o.transaction_hash).match(/.{1,2}/g).reverse()).join("")+'';
|
|
||||||
if(tx.match(/^[a-f0-9]+$/)){
|
|
||||||
var n = o.index;
|
|
||||||
var script = (redeem.redeemscript==true) ? redeem.decodedRs : all_info.address.script_hex;
|
|
||||||
var amount = ((o.value.toString()*1)/100000000).toFixed(8);
|
|
||||||
addOutput(tx, n, script, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function(data, status) {
|
|
||||||
$("#redeemFromBtn").html("Load").attr('disabled',false);
|
|
||||||
totalInputAmount();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* retrieve unspent data from chainso */
|
|
||||||
function listUnspentChainso(redeem, network){
|
|
||||||
$.ajax ({
|
|
||||||
type: "GET",
|
|
||||||
url: "https://chain.so/api/v2/get_tx_unspent/"+network+"/"+redeem.addr,
|
|
||||||
dataType: "json",
|
|
||||||
error: function(data) {
|
|
||||||
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs!');
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
if((data.status && data.data) && data.status=='success'){
|
|
||||||
$("#redeemFromAddress").removeClass('hidden').html('<span class="glyphicon glyphicon-info-sign"></span> Retrieved unspent inputs from address <a href="'+explorer_addr+redeem.addr+'" target="_blank">'+redeem.addr+'</a>');
|
|
||||||
for(var i in data.data.txs){
|
|
||||||
var o = data.data.txs[i];
|
|
||||||
var tx = ((""+o.txid).match(/.{1,2}/g).reverse()).join("")+'';
|
|
||||||
if(tx.match(/^[a-f0-9]+$/)){
|
|
||||||
var n = o.output_no;
|
|
||||||
var script = (redeem.redeemscript==true) ? redeem.decodedRs : o.script_hex;
|
|
||||||
var amount = o.value;
|
|
||||||
addOutput(tx, n, script, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$("#redeemFromStatus").removeClass('hidden').html('<span class="glyphicon glyphicon-exclamation-sign"></span> Unexpected error, unable to retrieve unspent outputs.');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function(data, status) {
|
|
||||||
$("#redeemFromBtn").html("Load").attr('disabled',false);
|
|
||||||
totalInputAmount();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* math to calculate the inputs and outputs */
|
/* math to calculate the inputs and outputs */
|
||||||
|
|
||||||
|
@ -1318,89 +1200,6 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// broadcast transaction via chain.so (mainnet)
|
|
||||||
function rawSubmitChainso(thisbtn, network){
|
|
||||||
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
|
|
||||||
$.ajax ({
|
|
||||||
type: "POST",
|
|
||||||
url: "https://chain.so/api/v2/send_tx/"+network+"/",
|
|
||||||
data: {"tx_hex":$("#rawTransaction").val()},
|
|
||||||
dataType: "json",
|
|
||||||
error: function(data) {
|
|
||||||
var obj = $.parseJSON(data.responseText);
|
|
||||||
var r = ' ';
|
|
||||||
r += (obj.data.tx_hex) ? obj.data.tx_hex : '';
|
|
||||||
r = (r!='') ? r : ' Failed to broadcast'; // build response
|
|
||||||
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
if(data.status && data.data.txid){
|
|
||||||
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden").html(' TXID: ' + data.data.txid + '<br> <a href="https://chain.so/tx/'+network+'/' + data.data.txid + '" target="_blank">View on Blockchain Explorer</a>');
|
|
||||||
} else {
|
|
||||||
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function(data, status) {
|
|
||||||
$("#rawTransactionStatus").fadeOut().fadeIn();
|
|
||||||
$(thisbtn).val('Submit').attr('disabled',false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// broadcast transaction via blockcypher.com (mainnet)
|
|
||||||
function rawSubmitblockcypher(thisbtn, network){
|
|
||||||
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
|
|
||||||
$.ajax ({
|
|
||||||
type: "POST",
|
|
||||||
url: "https://api.blockcypher.com/v1/"+network+"/main/txs/push",
|
|
||||||
data: JSON.stringify({"tx":$("#rawTransaction").val()}),
|
|
||||||
error: function(data) {
|
|
||||||
var r = 'Failed to broadcast: error code=' + data.status.toString() + ' ' + data.statusText;
|
|
||||||
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
if((data.tx) && data.tx.hash){
|
|
||||||
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden")
|
|
||||||
.html(' TXID: ' + data.tx.hash + '<br> <a href="https://live.blockcypher.com/'+network+'/tx/' + data.tx.hash + '" target="_blank">View on Blockchain Explorer</a>');
|
|
||||||
} else {
|
|
||||||
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function(data, status) {
|
|
||||||
$("#rawTransactionStatus").fadeOut().fadeIn();
|
|
||||||
$(thisbtn).val('Submit').attr('disabled',false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// broadcast transaction via blockchair
|
|
||||||
function rawSubmitblockchair(thisbtn, network){
|
|
||||||
$(thisbtn).val('Please wait, loading...').attr('disabled',true);
|
|
||||||
$.ajax ({
|
|
||||||
type: "POST",
|
|
||||||
url: "https://api.blockchair.com/"+network+"/push/transaction",
|
|
||||||
data: {"data":$("#rawTransaction").val()},
|
|
||||||
dataType: "json",
|
|
||||||
error: function(data) {
|
|
||||||
var r = 'Failed to broadcast: error code=' + data.status.toString() + ' ' + data.statusText;
|
|
||||||
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(r).prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
|
|
||||||
// console.error(JSON.stringify(data, null, 4));
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
// console.info(JSON.stringify(data, null, 4));
|
|
||||||
if((data.context && data.data) && data.context.code=='200'){
|
|
||||||
$("#rawTransactionStatus").addClass('alert-success').removeClass('alert-danger').removeClass("hidden")
|
|
||||||
.html(' TXID: ' + data.data.transaction_hash + '<br> <a href="https://blockchair.com/'+network+'/transaction/' + data.data.transaction_hash + '" target="_blank">View on Blockchain Explorer</a>');
|
|
||||||
} else {
|
|
||||||
$("#rawTransactionStatus").addClass('alert-danger').removeClass('alert-success').removeClass("hidden").html(' Unexpected error, please try again').prepend('<span class="glyphicon glyphicon-exclamation-sign"></span>');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: function(data, status) {
|
|
||||||
$("#rawTransactionStatus").fadeOut().fadeIn();
|
|
||||||
$(thisbtn).val('Submit').attr('disabled',false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1915,56 +1714,10 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
function configureBroadcast(){
|
function configureBroadcast(){
|
||||||
var host = $("#coinjs_broadcast option:selected").val();
|
|
||||||
|
|
||||||
// api: blockcypher blockchair chain.so
|
|
||||||
// network name "btc" "bitcoin" "BTC"
|
|
||||||
// network name "ltc" "litecoin" "LTC"
|
|
||||||
// network name "doge" "dogecoin" "DOGE"
|
|
||||||
|
|
||||||
$("#rawSubmitBtn").unbind("");
|
|
||||||
if(host=="chain.so_bitcoinmainnet"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitChainso(this, "BTC");
|
|
||||||
});
|
|
||||||
} else if(host=="chain.so_litecoin"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitChainso(this, "LTC");
|
|
||||||
});
|
|
||||||
} else if(host=="chain.so_dogecoin"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitChainso(this, "DOGE");
|
|
||||||
});
|
|
||||||
} else if(host=="blockcypher_bitcoinmainnet"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitblockcypher(this, "btc");
|
|
||||||
});
|
|
||||||
} else if(host=="blockcypher_litecoin"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitblockcypher(this, "ltc");
|
|
||||||
});
|
|
||||||
} else if(host=="blockcypher_dogecoin"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitblockcypher(this, "doge");
|
|
||||||
});
|
|
||||||
} else if(host=="blockchair_bitcoinmainnet"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitblockchair(this, "bitcoin");
|
|
||||||
});
|
|
||||||
} else if(host=="blockchair_litecoin"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitblockchair(this, "litecoin");
|
|
||||||
});
|
|
||||||
} else if(host=="blockchair_dogecoin"){
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
|
||||||
rawSubmitblockchair(this, "dogecoin");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$("#rawSubmitBtn").click(function(){
|
$("#rawSubmitBtn").click(function(){
|
||||||
rawSubmitDefault(this); // revert to default
|
rawSubmitDefault(this); // revert to default
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function configureGetUnspentTx(){
|
function configureGetUnspentTx(){
|
||||||
$("#redeemFromBtn").attr('rel',$("#coinjs_utxo option:selected").val());
|
$("#redeemFromBtn").attr('rel',$("#coinjs_utxo option:selected").val());
|
||||||
|
|
Loading…
Reference in a new issue