2023-03-13 16:52:24 -05:00
<!DOCTYPE html>
< html >
< head >
< meta charset = "UTF-8" >
2023-03-14 10:40:07 -05:00
< meta name = "viewport" content = "width=device-width, user-scalable=no" />
< link rel = "shortcut icon" type = "image/png" href = "favicon.png" >
< title > Inscribe the planet</ title >
2023-03-13 16:52:24 -05:00
< style >
* {
box-sizing : border-box ;
font-size : 1.15 rem ;
2023-03-14 14:49:03 -05:00
font-family : monospace ;
2023-03-13 16:52:24 -05:00
background-color : black ;
color : white ;
}
html {
max-width : 70 ch ;
padding : 3 rem 1 rem ;
margin : auto ;
line-height : 1.25 ;
}
h1 {
font-size : 2 rem ;
}
h2 {
font-size : 1.5 rem ;
}
input {
line-height : 1.25 ;
width : 100 % ;
height : 1.8 rem ;
font-size : 1.15 rem ;
border : 1 px solid white ;
}
. black-bg {
display : none ;
width : 100 % ;
position : fixed ;
top : 0 ;
left : 0 ;
background-color : black ;
opacity : .5 ;
width : 100 vw ;
height : 100 vh ;
}
. modal {
display : none ;
position : fixed ;
box-sizing : border-box ;
top : 50 % ;
left : 50 % ;
transform : translate ( -50 % , -50 % );
width : 100 % ;
max-width : 560 px ;
background-color : white ;
border-radius : 10 px ;
padding : 20 px ;
color : black ;
text-align : center ;
}
. display {
display : none ;
border : 1 px solid white ;
padding : 1 rem ;
border-radius : 1 rem ;
word-wrap : break-word ;
text-align : center ;
position : relative ;
}
. display p {
text-align : left ;
}
. checking_mempool , . checking_mempool span {
color : lightgreen ;
}
2023-03-14 10:40:07 -05:00
. feerates {
display : flex ;
justify-content : space-around ;
}
. fee {
width : 100 % ;
max-width : 6 rem ;
2023-03-14 14:45:27 -05:00
margin : 0 px 0.5 rem ;
2023-03-14 10:40:07 -05:00
text-align : center ;
cursor : pointer ;
}
. fee . num {
background-color : grey ;
border : 1 px solid white ;
padding : .3 rem ;
}
2023-03-16 09:41:28 -05:00
. minfee . num {
2023-03-14 10:40:07 -05:00
background-color : green ;
}
. safari_warning {
display : none ;
}
2023-03-16 12:32:20 -05:00
. registration , . upload_file {
text-decoration : underline ;
cursor : pointer ;
}
. dns_form , . dns_checker , . timer {
display : none ;
}
2023-03-13 16:52:24 -05:00
@ media screen and ( max-width : 600px ) {
}
</ style >
< script src = "https://unpkg.com/@cmdcode/bton@1.0.3" ></ script >
< script > const BTON = window . bton </ script >
< script src = "https://unpkg.com/@cmdcode/crypto-utils@1.5.11" ></ script >
< script src = "https://bundle.run/bech32@2.0.0" ></ script >
< script src = "https://supertestnet.github.io/bitcoin-chess/js/qrcode.js" ></ script >
< script >
var $ = document . querySelector . bind ( document );
var $$ = document . querySelectorAll . bind ( document );
var url_params = new URLSearchParams ( window . location . search );
var url_keys = url_params . keys ();
var $_GET = {}
for ( var key of url_keys ) $_GET [ key ] = url_params . get ( key );
</ script >
< script >
function encodeBase64 ( file ) {
return new Promise ( function ( resolve , reject ) {
//the next three lines handle the case where an image is passed in from an external site
if ( "files" in file ) {
file = file . files [ 0 ];
}
2023-03-15 10:54:09 -05:00
var mimetype = file . type ;
if ( mimetype . includes ( "text/plain" ) ) {
mimetype += ";charset=utf-8" ;
}
sessionStorage [ "mimetype" ] = mimetype ;
2023-03-13 16:52:24 -05:00
var imgReader = new FileReader ();
imgReader . onloadend = function () {
resolve ( imgReader . result . toString () );
}
imgReader . readAsDataURL ( file );
});
}
function base64ToHex ( str ) {
const raw = atob ( str );
let result = '' ;
for ( let i = 0 ; i < raw . length ; i ++ ) {
const hex = raw . charCodeAt ( i ). toString ( 16 );
result += ( hex . length === 2 ? hex : '0' + hex );
}
return result . toLowerCase ();
}
function hexToBytes ( hex ) {
return Uint8Array . from ( hex . match ( /.{1,2}/g ). map ( ( byte ) => parseInt ( byte , 16 ) ) );
}
function bytesToHex ( bytes ) {
return bytes . reduce ( ( str , byte ) => str + byte . toString ( 16 ). padStart ( 2 , "0" ), "" );
}
2023-03-16 12:32:20 -05:00
function textToHex ( text ) {
var encoder = new TextEncoder (). encode ( text );
return [... new Uint8Array ( encoder )]
. map ( x => x . toString ( 16 ). padStart ( 2 , "0" ) )
. join ( "" );
}
2023-03-13 16:52:24 -05:00
function createQR ( content ) {
var dataUriPngImage = document . createElement ( "img" ),
s = QRCode . generatePNG ( content , {
ecclevel : "M" ,
format : "html" ,
fillcolor : "#FFFFFF" ,
textcolor : "#000000" ,
margin : 4 ,
modulesize : 8 ,
});
dataUriPngImage . src = s ;
dataUriPngImage . id = "qr_code" ;
return dataUriPngImage ;
}
async function getBitcoinPriceFromCoinbase () {
var data = await getData ( "https://api.coinbase.com/v2/prices/BTC-USD/spot" );
var json = JSON . parse ( data );
var price = json [ "data" ][ "amount" ];
return price ;
}
async function getBitcoinPriceFromKraken () {
var data = await getData ( "https://api.kraken.com/0/public/Ticker?pair=XBTUSD" );
var json = JSON . parse ( data );
var price = json [ "result" ][ "XXBTZUSD" ][ "a" ][ 0 ];
return price ;
}
async function getBitcoinPriceFromCoindesk () {
var data = await getData ( "https://api.coindesk.com/v1/bpi/currentprice.json" );
var json = JSON . parse ( data );
var price = json [ "bpi" ][ "USD" ][ "rate_float" ];
return price ;
}
async function getBitcoinPriceFromGemini () {
var data = await getData ( "https://api.gemini.com/v2/ticker/BTCUSD" );
var json = JSON . parse ( data );
var price = json [ "bid" ];
return price ;
}
async function getBitcoinPriceFromBybit () {
var data = await getData ( "https://api-testnet.bybit.com/derivatives/v3/public/order-book/L2?category=linear&symbol=BTCUSDT" );
var json = JSON . parse ( data );
var price = json [ "result" ][ "b" ][ 0 ][ 0 ];
return price ;
}
async function getBitcoinPrice () {
var prices = [];
var cbprice = await getBitcoinPriceFromCoinbase ();
var kprice = await getBitcoinPriceFromKraken ();
var cdprice = await getBitcoinPriceFromCoindesk ();
var gprice = await getBitcoinPriceFromGemini ();
var bprice = await getBitcoinPriceFromBybit ();
prices . push ( Number ( cbprice ), Number ( kprice ), Number ( cdprice ), Number ( gprice ), Number ( bprice ) );
prices . sort ();
return prices [ 2 ];
}
</ script >
</ head >
< body >
< h1 > Welcome to the online inscriber</ h1 >
2023-03-14 10:40:07 -05:00
< h2 class = "safari_warning" > This tool may not work in safari browser. If you are using that, consider switching.</ h2 >
< p > First enter a < span class = "type_of_address" > taproot</ span > address from an ordinal wallet</ p >
2023-03-13 16:52:24 -05:00
< p >< input class = "address" ></ p >
2023-03-16 12:32:20 -05:00
< p class = "instructions" > Then upload a file you want that address to own or < span class = "registration" > click here</ span > to register a domain name</ p >
2023-03-13 16:52:24 -05:00
< form >
2023-03-16 12:32:20 -05:00
< p class = "file_form" >< input type = "file" class = "form" ></ p >
< p class = "dns_form" >< input class = "dns" placeholder = "example: lol.sats" ></ p >
< p >< button class = "dns_checker" type = "button" > Check availability</ button > < span class = "timer" > 61</ span ></ p >
2023-03-14 10:40:07 -05:00
< p > Select a feerate (measured in sats per byte)</ p >
< div class = "feerates" >< div class = "fee minfee" >< div class = "num" > ...</ div >< div class = "name" > Min</ div ></ div >< div class = "fee midfee" >< div class = "num" > ...</ div >< div class = "name" > Mid</ div ></ div >< div class = "fee maxfee" >< div class = "num" > ...</ div >< div class = "name" > Max</ div ></ div ></ div >
< div id = "sliderange" >
< p > Sats per byte: < span id = "sats_per_byte" > 1</ span ></ p >
< input id = "sats_range" type = "range" min = "1" max = "100" value = "1" >
</ div >
< script >
var slider = document . getElementById ( "sats_range" );
var output = document . getElementById ( "sats_per_byte" );
output . innerHTML = slider . value ;
slider . oninput = function () {
output . innerHTML = this . value ;
sessionStorage [ "feerate" ] = this . value ;
$$ ( '.fee .num' ). forEach ( function ( item ) {
item . style . backgroundColor = "grey" ;
});
}
</ script >
2023-03-13 16:52:24 -05:00
</ form >
< p >< button class = "submit" > Submit</ button ></ p >
< div class = "display" ></ div >
< div style = "display: none;" class = "file" ></ div >
< script >
sessionStorage.clear();
2023-03-14 10:40:07 -05:00
const privkey = bytesToHex( cryptoUtils.Noble.utils.randomPrivateKey() );
2023-03-16 12:32:20 -05:00
function showRegister() {
$( '.file_form' ).style.display = "none";
$( '.dns_form' ).style.display = "block";
$( '.dns_checker' ).style.display = "inline";
$( '.dns' ).value = "";
$( '.instructions' ).innerHTML = `Enter a domain name you want to register or < span class = "upload_file" > click here</ span > to upload a file instead.`;
$( '.upload_file' ).onclick = showUploader;
}
function showUploader() {
$( '.file_form' ).style.display = "block";
$( '.dns_form' ).style.display = "none";
$( '.dns_checker' ).style.display = "none";
$( '.instructions' ).innerHTML = `Then upload a file you want that address to own or < span class = "registration" > click here</ span > to register a domain name`;
$( '.registration' ).onclick = showRegister;
}
showUploader();
2023-03-13 16:52:24 -05:00
$( '.form' ).addEventListener( "change", async function() {
2023-03-14 10:40:07 -05:00
if ( this.files[ 0 ].size >= 120000 && this.files[ 0 ].size < 350000 ) {
var conf = confirm( " You exceeded the 120 kb size limit . Click ok to override this warning or click cancel to try again ." );
if ( conf ) {
var b64 = await encodeBase64 ( this );
} else {
this . value = null;
}
} else if ( this . files [ 0 ]. size > = 350000 ) {
alert( "You exceeded this software's hard size limit of 350 kb files. Modify the code to override the limit." )
this.value = null;
2023-03-13 16:52:24 -05:00
} else {
2023-03-14 10:40:07 -05:00
var b64 = await encodeBase64( this );
2023-03-13 16:52:24 -05:00
}
var base64 = b64.substring( b64.indexOf( "base64," ) + 7 );
var hex = base64ToHex( base64 );
// console.log( "hex:", hex );
// console.log( "bytes:", hexToBytes( hex ) );
$( '.file' ).innerText = hex;
});
$( '.submit' ).addEventListener( "click", async function() {
2023-03-16 12:32:20 -05:00
if ( $( '.file_form' ).style.display == "none" ) {
sessionStorage[ "mimetype" ] = "text/plain;charset=utf-8";
var domain = {"p":"sns","op":"reg","name":$( '.dns' ).value}
$( '.file' ).innerText = textToHex( JSON.stringify( domain ) );
}
2023-03-13 16:52:24 -05:00
const ec = new TextEncoder();
const hex = $( '.file' ).innerText;
const data = hexToBytes( hex );
const KeyPair = cryptoUtils.KeyPair;
const seckey = new KeyPair(privkey);
const pubkey = seckey.pub.rawX;
const mimetype = ec.encode( sessionStorage[ "mimetype" ] );
const script = [ pubkey, 'OP_CHECKSIG', 'OP_0', 'OP_IF', ec.encode('ord'), '01', mimetype, 'OP_0', data, 'OP_ENDIF' ];
const leaf = await BTON.Tap.getLeaf(BTON.Script.encode(script));
const [ tapkey ] = await BTON.Tap.getPubkey(pubkey, [ leaf ]);
const cblock = await BTON.Tap.getPath(pubkey, leaf);
console.log('Tapkey:', tapkey);
var fundingAddress = BTON.Tap.encodeAddress( tapkey, 'tb' );
console.log('Funding address: ', fundingAddress );
//var toAddress = prompt( "give me the address you your inscription to arrive in and consider using this one: tb1padwymyc6x2dfc3cwzvpxxcqsr3c46cjx9zxg0jmcuf44fjuwljxs7x68fm" );
//var toAddress = "tb1padwymyc6x2dfc3cwzvpxxcqsr3c46cjx9zxg0jmcuf44fjuwljxs7x68fm";
var toAddress = $( '.address' ).value;
console.log('Address that will receive the inscription:', toAddress );
var decodedToAddress = "5120" + BTON.Tap.decodeAddress( toAddress ).hex;
console.log('To address decoded:', decodedToAddress );
var txsize = 200 + ( hex.length / 2 );
2023-03-14 10:40:07 -05:00
if ( sessionStorage[ "feerate" ] ) {
var feerate = Number( sessionStorage[ "feerate" ] );
2023-03-16 13:37:47 -05:00
sessionStorage[ "determined_feerate" ] = sessionStorage[ "feerate" ];
2023-03-14 10:40:07 -05:00
} else {
2023-03-16 09:41:28 -05:00
var feerate = await getMinFeeRate();
2023-03-16 13:37:47 -05:00
sessionStorage[ "determined_feerate" ] = sessionStorage[ "feerate" ];
2023-03-14 10:40:07 -05:00
}
2023-03-13 16:52:24 -05:00
var fee = feerate * txsize;
var btc_price = sessionStorage[ "bitcoin_price" ];
var sats_price = await satsToDollars( fee + 1000 );
sats_price = Math.floor( sats_price * 100 ) / 100;
var html = `< p > Please send at least ${fee + 1000} sats ($${sats_price}) to this address:</ p >< p > ${fundingAddress}</ p > `;
$( '.display' ).innerHTML = html;
var qr_value = "bitcoin:" + fundingAddress + "?amount=" + satsToBitcoin( fee + 1000 );
console.log( "qr:", qr_value );
$( '.display' ).append( createQR( qr_value ) );
$( '.display' ).innerHTML += `< p class = "checking_mempool" > Checking the mempool< span class = "dots" > .</ span ></ p > `;
$( '.display' ).innerHTML += `< p > 1000 sats will go to the address</ p >< p > ${fee} sats will go to miners as a mining fee</ p > `;
$( '.display' ).style.display = "block";
await loopTilAddressReceivesMoney( fundingAddress );
await waitSomeSeconds( 2 );
var txinfo = await addressReceivedMoneyInThisTx( fundingAddress );
var txid = txinfo[ 0 ];
var vout = txinfo[ 1 ];
var amt = txinfo[ 2 ];
2023-03-14 10:40:07 -05:00
// if ( !txid || !vout || !amt ) {
// await waitSomeSeconds( 2 );
// txinfo = await addressReceivedMoneyInThisTx( fundingAddress );
// txid = txinfo[ 0 ];
// vout = txinfo[ 1 ];
// amt = txinfo[ 2 ];
// }
2023-03-13 16:52:24 -05:00
// var amt = prompt( "give me the amount you sent" );
// amt = Number( amt );
// var txid = prompt( "give me the txid" );
// var vout = prompt( "give me the vout" );
// vout = Number( vout );
console.log( "yay! txid:", txid, "vout:", vout, "amount:", amt );
2023-03-16 13:37:47 -05:00
if ( sessionStorage[ "determined_feerate" ] ) {
feerate = Number( sessionStorage[ "determined_feerate" ] );
2023-03-14 10:40:07 -05:00
} else {
2023-03-16 09:41:28 -05:00
feerate = await getMinFeeRate();
2023-03-14 10:40:07 -05:00
}
var fee = feerate * txsize;
2023-03-13 16:52:24 -05:00
console.log( "feerate:", feerate, "txsize:", txsize, "fee:", fee );
console.log( "fee:", fee );
const redeemtx = {
version: 2,
input: [{
txid: txid,
vout: vout,
prevout: { value: amt, scriptPubKey: '5120' + tapkey },
witness: []
}],
output:[{
value: amt - fee,
scriptPubKey: decodedToAddress
}],
locktime: 0
}
const sec = await BTON.Tap.getSeckey(seckey.raw, [ leaf ]);
2023-03-14 12:14:30 -05:00
const sig = await BTON.Sig.taproot.sign(seckey.raw, redeemtx, 0, { extention: leaf });
2023-03-13 16:52:24 -05:00
redeemtx.input[0].witness = [ sig, script, cblock ];
console.dir(redeemtx, { depth: null });
//await BTON.Sig.taproot.verify(redeemtx, 0, {extension: leaf}, true);
var rawtx = BTON.Tx.encode(redeemtx);
console.log('Txdata:', rawtx );
var txid = await pushBTCpmt( rawtx );
2023-03-16 13:00:45 -05:00
var html = `< p style = "background-color: white; color: black;" > Success! Your file will shortly be inscribed on the bitcoin blockchain in this transaction:</ p >< p style = "word-wrap: break-word;" >< a href = "https://mempool.space/testnet/tx/${txid}" target = "_blank" > https://mempool.space/testnet/tx/${txid}</ a ></ p > `;
2023-03-14 10:40:07 -05:00
html += `< p style = "background-color: white; color: black;" > When your transaction confirms you can view it on the ordinals explorer here:</ p >< p style = "word-wrap: break-word;" >< a href = "https://ordinals.com/inscription/${txid}i0" target = "_blank" > https://ordinals.com/inscription/${txid}i0</ a ></ p > `;
2023-03-13 16:52:24 -05:00
$( '.modal' ).innerHTML = html;
$( '.modal' ).style.display = "block";
$( '.black-bg' ).style.display = "block";
});
2023-03-14 10:40:07 -05:00
async function getMaxFeeRate() {
var fees = await getData( "https://mempool.space/testnet/api/v1/fees/recommended" );
2023-03-13 16:52:24 -05:00
fees = JSON.parse( fees );
2023-03-14 10:40:07 -05:00
// if ( !( "minimumFee" in fees ) ) return "error -- site down";
// var minfee = fees[ "minimumFee" ];
if ( !( "fastestFee" in fees ) ) return "error -- site down";
2023-03-16 09:41:28 -05:00
var maxfee = fees[ "fastestFee" ];
return maxfee;
}
async function getMinFeeRate() {
var fees = await getData( "https://mempool.space/testnet/api/v1/fees/recommended" );
fees = JSON.parse( fees );
if ( !( "minimumFee" in fees ) ) return "error -- site down";
var minfee = fees[ "minimumFee" ];
// if ( !( "fastestFee" in fees ) ) return "error -- site down";
// var maxfee = fees[ "fastestFee" ];
2023-03-13 16:52:24 -05:00
return minfee;
}
2023-03-14 10:40:07 -05:00
function isValidTaprootAddress( address ) {
try {
BTON.Tap.decodeAddress( address ).hex;
return true;
} catch( e ) {}
return;
}
async function getAllFeeRates() {
var fees = await getData( "https://mempool.space/testnet/api/v1/fees/recommended" );
fees = JSON.parse( fees );
return fees;
}
2023-03-16 15:17:13 -05:00
function isValidJson( content ) {
if ( !content ) return;
try {
var json = JSON.parse( content );
} catch ( e ) {
return;
}
return true;
}
2023-03-13 16:52:24 -05:00
function getData( url ) {
return new Promise( async function( resolve, reject ) {
function inner_get( url ) {
var xhttp = new XMLHttpRequest();
xhttp.open( "GET", url, true );
xhttp.send();
return xhttp;
}
var data = inner_get( url );
data.onerror = function( e ) {
resolve( "error" );
}
async function isResponseReady() {
return new Promise( function( resolve2, reject ) {
if ( !data.responseText || data.readyState != 4 ) {
setTimeout( async function() {
var msg = await isResponseReady();
resolve2( msg );
}, 1 );
} else {
resolve2( data.responseText );
}
});
}
var returnable = await isResponseReady();
resolve( returnable );
});
}
async function pushBTCpmt( rawtx ) {
var txid = await postData( "https://mempool.space/testnet/api/tx", rawtx );
return txid;
}
function waitSomeSeconds( num ) {
var num = num.toString() + "000";
num = Number( num );
return new Promise( function( resolve, reject ) {
setTimeout( function() { resolve( "" ); }, num );
});
}
async function postData( url, json, content_type = "", apikey = "" ) {
var rtext = "";
function inner_post( url, json, content_type = "", apikey = "" ) {
var xhttp = new XMLHttpRequest();
xhttp.open( "POST", url, true );
if ( content_type ) {
xhttp.setRequestHeader( `Content-Type`, content_type );
}
if ( apikey ) {
xhttp.setRequestHeader( `X-Api-Key`, apikey );
}
xhttp.send( json );
return xhttp;
}
var data = inner_post( url, json, content_type, apikey );
data.onerror = function( e ) {
rtext = "error";
}
async function isResponseReady() {
return new Promise( function( resolve, reject ) {
if ( rtext == "error" ) {
resolve( rtext );
}
if ( !data.responseText || data.readyState != 4 ) {
setTimeout( async function() {
var msg = await isResponseReady();
resolve( msg );
}, 50 );
} else {
resolve( data.responseText );
}
});
}
var returnable = await isResponseReady();
return returnable;
}
async function loopTilAddressReceivesMoney( address ) {
var itReceivedMoney = false;
async function isDataSetYet( data_i_seek ) {
return new Promise( function( resolve, reject ) {
if ( !data_i_seek ) {
setTimeout( async function() {
console.log( "waiting for address to receive money..." );
itReceivedMoney = await addressOnceHadMoney( address );
var msg = await isDataSetYet( itReceivedMoney );
resolve( msg );
}, 2000 );
} else {
resolve( data_i_seek );
}
});
}
async function getTimeoutData() {
var data_i_seek = await isDataSetYet( itReceivedMoney );
return data_i_seek;
}
var returnable = await getTimeoutData();
return returnable;
}
async function addressReceivedMoneyInThisTx( address ) {
var txid;
var vout;
var amt;
var nonjson = await getData( "https://mempool.space/testnet/api/address/" + address + "/txs" );
var json = JSON.parse( nonjson );
json.forEach( function( tx ) {
tx[ "vout" ].forEach( function( output, index ) {
if ( output[ "scriptpubkey_address" ] == address ) {
txid = tx[ "txid" ];
vout = index;
amt = output[ "value" ];
}
});
});
return [txid, vout, amt];
}
async function addressOnceHadMoney( address ) {
var url = "https://mempool.space/testnet/api/address/" + address;
var nonjson = await getData( url );
2023-03-16 13:18:13 -05:00
if ( !isValidJson( nonjson ) ) return false;
2023-03-13 16:52:24 -05:00
var json = JSON.parse( nonjson );
if ( json[ "chain_stats" ][ "tx_count" ] > 0 || json[ "mempool_stats" ][ "tx_count" ] > 0 ) {
return true;
}
return false;
}
function dotLoop( string ) {
if ( !$( '.dots' ) ) {
setTimeout( function() {dotLoop( string );}, 1000 );
return;
}
if ( string.length < 3 ) {
string = string + ".";
} else {
string = "." ;
}
$( '. dots ' ). innerText = string;
setTimeout ( function () { dotLoop ( string );}, 1000 );
}
dotLoop ( "." );
2023-03-16 12:32:20 -05:00
function timer ( num ) {
if ( ! num ) {
$( '. timer ' ). style . display = "none" ;
return ;
}
num = num - 1 ;
$( '. timer ' ). innerText = num;
setTimeout ( function () { timer ( num );}, 1000 );
}
2023-03-13 16:52:24 -05:00
function satsToBitcoin ( sats ) {
if ( sats > = 100000000 ) sats = sats * 10;
var string = String( sats ).padStart( 8, "0" ).slice( 0,-9 ) + "." + String( sats ).padStart( 8, "0" ).slice( -9 );
if ( string.substring( 0, 1 ) == "." ) string = "0" + string;
return string;
}
async function satsToDollars( sats ) {
if ( sats >= 100000000 ) sats = sats * 10;
var bitcoin_price = sessionStorage[ "bitcoin_price" ];
var value_in_dollars = Number( String( sats ).padStart( 8, "0" ).slice( 0,-9 ) + "." + String( sats ).padStart( 8, "0" ).slice( -9 ) ) * bitcoin_price;
return value_in_dollars;
}
function modalVanish() {
$( ".black-bg" ).style.display = "none";
$( ".modal" ).style.display = "none";
}
2023-03-14 10:40:07 -05:00
$$( '.fee' ).forEach( function( item ) {
item.onclick = function() {
$$( '.fee .num' ).forEach( function( item2 ) {
item2.style.backgroundColor = "grey";
});
this.getElementsByClassName( "num" )[ 0 ].style.backgroundColor = "green";
sessionStorage[ "feerate" ] = this.getElementsByClassName( "num" )[ 0 ].innerText;
$( '#sats_per_byte' ).innerText = Number( this.getElementsByClassName( "num" )[ 0 ].innerText );
$( '#sats_range' ).value = Number( this.getElementsByClassName( "num" )[ 0 ].innerText );
}
});
function checkAddress() {
2023-03-16 12:32:20 -05:00
if ( $( '.address' ).value && !isValidTaprootAddress( $( '.address' ).value ) ) {
2023-03-14 10:40:07 -05:00
$( '.address' ).style.backgroundColor = "#ff5252";
$( '.address' ).style.border = "2px solid red";
$( '.type_of_address' ).style.border = "1px solid white";
} else {
$( '.address' ).style.backgroundColor = "initial";
$( '.address' ).style.border = "1px solid white";
$( '.type_of_address' ).style.borderStyle = "none";
}
}
$( '.address' ).onchange = checkAddress;
$( '.address' ).onpaste = checkAddress;
$( '.address' ).onkeyup = checkAddress;
2023-03-16 12:32:20 -05:00
async function isUsedDomain( domain ) {
var data = await getData( `https://api.sats.id/names/${domain}` );
console.log( "data:", data );
data = JSON.parse( data );
console.log( "data:", data );
if ( "name" in data ) return true;
if ( data[ "error" ] == "Too many requests" ) return;
return false;
}
async function checkDomain() {
var isUsed = await isUsedDomain( $( '.dns' ).value );
if ( $( '.dns' ).value && isUsed ) {
alert( `This domain is already registered, please try a different one` );
} else if ( $( '.dns' ).value && isUsed == undefined ) {
timer( 61 );
$( '.timer' ).style.display = "inline";
alert( `You can only check one domain per minute, please try again in another minute` );
} else {
alert( `This domain is available, go for it!` );
}
}
$( '.dns_checker' ).onclick = checkDomain;
2023-03-14 10:40:07 -05:00
async function init( num ) {
if ( !num ) {
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
if ( isSafari ) $( '.safari_warning' ).style.display = "block";
2023-03-16 09:41:28 -05:00
var minfee = await getMinFeeRate();
$( '#sats_per_byte' ).innerText = minfee;
$( '#sats_range' ).value = minfee;
2023-03-14 10:40:07 -05:00
}
num = num + 1;
var allrates = await getAllFeeRates();
$( '.minfee .num' ).innerText = allrates[ "minimumFee" ];
$( '.midfee .num' ).innerText = allrates[ "hourFee" ];
$( '.maxfee .num' ).innerText = allrates[ "fastestFee" ];
2023-03-15 13:16:50 -05:00
var isgreen;
$$( '.fee .num' ).forEach( function( item ) {
2023-03-15 13:23:16 -05:00
if ( item.style.backgroundColor == "green" || getComputedStyle( item ).backgroundColor == "rgb(0, 128, 0)" ) isgreen = item;
2023-03-15 13:16:50 -05:00
});
if ( isgreen ) {
$( '#sats_per_byte' ).innerText = Number( isgreen.innerText );
$( '#sats_range' ).value = Number( isgreen.innerText );
sessionStorage[ "feerate" ] = isgreen.innerText;
}
2023-03-13 16:52:24 -05:00
sessionStorage[ "bitcoin_price" ] = await getBitcoinPrice();
await waitSomeSeconds( 10 );
2023-03-14 10:40:07 -05:00
init( num );
2023-03-13 16:52:24 -05:00
}
2023-03-14 10:40:07 -05:00
init( 0 );
2023-03-13 16:52:24 -05:00
</ script >
< div class = "black-bg" onclick = "modalVanish();" ></ div >
< div class = "modal" ></ div >
</ body >
</ html >