Files
inscriboor/index.html
T

1422 lines
47 KiB
HTML
Raw Normal View History

2023-03-14 10:27:09 -05:00
<!DOCTYPE html>
<html>
2023-03-29 02:37:31 +02:00
<head>
<meta charset="UTF-8">
2023-04-01 19:41:32 +02:00
<meta name="viewport" content="width=device-width, user-scalable=no"/>
2023-03-29 02:37:31 +02:00
<link rel="shortcut icon" type="image/png" href="favicon.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<title>Inscribe the planet</title>
<style>
2023-04-01 19:41:32 +02:00
* {
box-sizing: border-box;
font-size: 1.15rem;
font-family: monospace;
background-color: black;
color: white;
}
html {
max-width: 70ch;
padding: 3rem 1rem;
margin: auto;
line-height: 1.25;
}
ul li a{
text-decoration: none !important;
}
a.active:before
{
content : '['
}
a.active:after
{
content : ']'
}
h1 {
font-size: 2rem;
}
h2 {
font-size: 1.5rem;
}
label
{
display: block;
margin-bottom: 10px;
}
input {
line-height: 1.25;
width: 100%;
height: 1.8rem;
font-size: 1.15rem;
border: 1px solid white;
margin-bottom: 10px;
}
.black-bg{
display:none;
2023-03-29 02:37:31 +02:00
width:100%;
2023-04-01 19:41:32 +02:00
position:fixed;
top:0;
left:0;
background-color:black;
opacity:.5;
width:100vw;
height:100vh;
}
.modal {
display: none;
position: fixed;
box-sizing: border-box;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
max-width: 560px;
2023-03-29 02:37:31 +02:00
max-height: 100vh;
2023-04-01 19:41:32 +02:00
background-color: white;
2023-03-29 02:37:31 +02:00
padding: 20px;
2023-04-01 19:41:32 +02:00
color: black;
text-align: center;
2023-03-29 02:37:31 +02:00
border-radius: 25px;
border: 2px solid var(--primary-color);
}
2023-04-01 19:41:32 +02:00
.modal-content {
2023-03-29 02:37:31 +02:00
overflow-y: auto;
max-height: 85vh;
2023-04-01 19:41:32 +02:00
background-color: white;
color: black;
text-align: center;
2023-03-29 02:37:31 +02:00
border: transparent;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.display {
display: none;
border: 1px solid white;
padding: 1rem;
border-radius: 1rem;
word-wrap: break-word;
text-align: center;
position: relative;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.display p {
text-align: left;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.checking_mempool, .checking_mempool span {
color: lightgreen;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.feerates {
display: flex;
justify-content: space-around;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.fee {
width: 100%;
max-width: 6rem;
margin: 0px 0.5rem;
text-align: center;
cursor: pointer;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.fee .num {
background-color: grey;
border: 1px solid white;
padding: .3rem;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.minfee .num {
background-color: green;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.safari_warning {
display: none;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.registration, .upload_file {
2023-04-01 19:41:32 +02:00
text-decoration: underline;
2023-03-29 02:37:31 +02:00
cursor: pointer;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
.dns_form, .dns_checker, .timer, .brc20_deploy_form, .brc20_mint_form {
display: none;
}
</style>
<script src="https://bundle.run/buffer@6.0.3"></script>
<script> const buf = buffer </script>
<script src="bton.min.js"></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>
2023-04-01 19:41:32 +02:00
let $ = document.querySelector.bind(document);
let $$ = document.querySelectorAll.bind(document);
let url_params = new URLSearchParams(window.location.search);
2023-03-29 02:37:31 +02:00
let url_keys = url_params.keys();
let $_GET = {}
2023-04-01 19:41:32 +02:00
for (let key of url_keys) $_GET[key] = url_params.get(key);
2023-03-29 02:37:31 +02:00
</script>
<script>
2023-04-01 19:41:32 +02:00
function encodeBase64(file) {
return new Promise(function (resolve, reject) {
2023-03-29 02:37:31 +02:00
let imgReader = new FileReader();
2023-04-01 19:41:32 +02:00
imgReader.onloadend = function () {
resolve(imgReader.result.toString());
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
imgReader.readAsDataURL(file);
2023-03-29 02:37:31 +02:00
});
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
function base64ToHex(str) {
const raw = atob(str);
let result = '';
for (let i = 0; i < raw.length; i++) {
2023-03-14 10:27:09 -05:00
const hex = raw.charCodeAt(i).toString(16);
result += (hex.length === 2 ? hex : '0' + hex);
}
2023-03-29 02:37:31 +02:00
return result.toLowerCase();
}
2023-04-01 19:41:32 +02:00
function hexToBytes(hex) {
return Uint8Array.from(hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
function bytesToHex(bytes) {
return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
function textToHex(text) {
var encoder = new TextEncoder().encode(text);
2023-03-29 02:37:31 +02:00
return [...new Uint8Array(encoder)]
2023-04-01 19:41:32 +02:00
.map(x => x.toString(16).padStart(2, "0"))
.join("");
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
function createQR(content) {
let dataUriPngImage = document.createElement("img"),
s = QRCode.generatePNG(content, {
2023-03-14 10:27:09 -05:00
ecclevel: "M",
format: "html",
fillcolor: "#FFFFFF",
textcolor: "#000000",
margin: 4,
modulesize: 8,
});
2023-03-29 02:37:31 +02:00
dataUriPngImage.src = s;
dataUriPngImage.id = "qr_code";
return dataUriPngImage;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
async function getBitcoinPriceFromCoinbase() {
2023-04-01 19:41:32 +02:00
let data = await getData("https://api.coinbase.com/v2/prices/BTC-USD/spot");
let json = JSON.parse(data);
let price = json["data"]["amount"];
2023-03-29 02:37:31 +02:00
return price;
}
2023-03-14 10:27:09 -05:00
2023-03-29 02:37:31 +02:00
async function getBitcoinPriceFromKraken() {
2023-04-01 19:41:32 +02:00
let data = await getData("https://api.kraken.com/0/public/Ticker?pair=XBTUSD");
let json = JSON.parse(data);
let price = json["result"]["XXBTZUSD"]["a"][0];
2023-03-29 02:37:31 +02:00
return price;
}
2023-03-14 10:27:09 -05:00
2023-03-29 02:37:31 +02:00
async function getBitcoinPriceFromCoindesk() {
2023-04-01 19:41:32 +02:00
let data = await getData("https://api.coindesk.com/v1/bpi/currentprice.json");
let json = JSON.parse(data);
let price = json["bpi"]["USD"]["rate_float"];
2023-03-29 02:37:31 +02:00
return price;
}
2023-03-14 10:27:09 -05:00
2023-03-29 02:37:31 +02:00
async function getBitcoinPriceFromGemini() {
2023-04-01 19:41:32 +02:00
let data = await getData("https://api.gemini.com/v2/ticker/BTCUSD");
let json = JSON.parse(data);
let price = json["bid"];
2023-03-29 02:37:31 +02:00
return price;
}
2023-03-14 10:27:09 -05:00
2023-03-29 02:37:31 +02:00
async function getBitcoinPriceFromBybit() {
2023-04-01 19:41:32 +02:00
let data = await getData("https://api-testnet.bybit.com/derivatives/v3/public/order-book/L2?category=linear&symbol=BTCUSDT");
let json = JSON.parse(data);
let price = json["result"]["b"][0][0];
2023-03-29 02:37:31 +02:00
return price;
}
async function getBitcoinPrice() {
let prices = [];
let cbprice = await getBitcoinPriceFromCoinbase();
let kprice = await getBitcoinPriceFromKraken();
let cdprice = await getBitcoinPriceFromCoindesk();
let gprice = await getBitcoinPriceFromGemini();
let bprice = await getBitcoinPriceFromBybit();
2023-04-01 19:41:32 +02:00
prices.push(Number(cbprice), Number(kprice), Number(cdprice), Number(gprice), Number(bprice));
2023-03-29 02:37:31 +02:00
prices.sort();
2023-04-01 19:41:32 +02:00
return prices[2];
2023-03-29 02:37:31 +02:00
}
</script>
</head>
<body>
2023-04-01 19:41:32 +02:00
<h1>Ordinals Inscriber</h1>
<h6 style="margin-top: -15px;">Self-custodial. A free service hosted by <a href="https://rarity.garden" target="_blank">RarityGarden</a>.</h6>
<h2 class="safari_warning">This tool may not work in safari browser. If you are using that, consider switching.</h2>
<div id="setup">
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
<div class="mb-3">
<label for="taproot_address">Receiving address <span class="type_of_address">(taproot)</span></label>
<input id="taproot_address" class="address"
placeholder="Enter a taproot address from an ordinals wallet">
</div>
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
<p>Please choose what you want to inscribe:</p>
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
<ul>
<li>
<a id="upload_file_nav" class="upload_file active" href="javascript:void(0);">files</a>
</li>
<li>
<a id="registration_nav" class="registration" href="javascript:void(0);">.sats domains</a>
</li>
<li>
<a id="brc20_mint_nav" class="brc20_mint" href="javascript:void(0);">brc-20 mint</a>
</li>
<li class="nav-item">
<a id="brc20_deploy_nav" class="brc20_deploy" href="javascript:void(0);">brc-20 deploy</a>
</li>
</ul>
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
<form id="app-form">
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
<div class="file_form">
<input
accept=".json,
.pdf,
.asc,
.yaml,
.yml,
.flac,
.mp3,
.wav,
.apng,
.avif,
.gif,
.jpg,
.jpeg,
.png,
.svg,
.webp,
.glb,
.stl,
.html,
.txt,
.mp4,
.webm
" type="file" class="form" multiple>
2023-03-14 10:27:09 -05:00
2023-04-01 19:41:32 +02:00
<button style="margin-top: 15px;" id="bytes_checker" type="button" class="btn btn-outline-primary mb-3">
Check if file(s) are inscribed already
</button>
</div>
<div class="dns_form">
<textarea class="dns" style="width: 100%; height: 250px;"
placeholder="One domain per line. Example:&#10;&#10;ordi.sats&#10;btc.sats"></textarea>
</div>
<div class="brc20_mint_form">
<div class="mb-3">
<label for="brc20-mint-ticker">Ticker</label>
<input id="brc20-mint-ticker" type="text" maxlength="4" value=""
placeholder="e.g. ordi"/>
</div>
<div class="mb-3">
<label for="brc20-mint-amount">Amount</label>
<input id="brc20-mint-amount" type="text" value="" placeholder="e.g. 1000"/>
</div>
<div class="mb-3">
<label for="brc20-mint-repeat">Repeat</label>
<input id="brc20-mint-repeat" type="text" value="1"
placeholder="e.g. 10 to mint ten times"/>
</div>
</div>
<div class="brc20_deploy_form">
<div class="mb-3">
<label for="brc20-deploy-ticker">Ticker</label>
<input id="brc20-deploy-ticker" type="text" maxlength="4" value=""
placeholder="e.g. ordi"/>
</div>
<div class="mb-3">
<label for="brc20-deploy-max">Supply</label>
<input id="brc20-deploy-max" type="text" value="" placeholder="e.g. 21000000"/>
</div>
<div class="mb-3">
<label for="brc20-deploy-lim">Limit per mint</label>
<input id="brc20-deploy-lim" type="text" value="" placeholder="e.g. 1000"/>
</div>
</div>
<button class="dns_checker btn btn-outline-primary mt-3 mb-3" type="button">Check availability</button>
<span class="timer">61</span>
<p>Select a feerate (sats/vB)</p>
<div class="feerates">
<div class="fee minfee">
<div style="color: white;" class="num rounded">...</div>
<div class="name">Min</div>
</div>
<div class="fee midfee">
<div style="color: white;" class="num rounded">...</div>
<div class="name">Mid</div>
</div>
<div class="fee maxfee">
<div style="color: white;" class="num rounded">...</div>
<div class="name">Max</div>
2023-03-14 10:27:09 -05:00
</div>
2023-03-29 02:37:31 +02:00
</div>
2023-04-01 19:41:32 +02:00
<div id="sliderange">
<label for="sats_range">sats/vB: <span id="sats_per_byte">1</span></label>
<input class="form-range" id="sats_range" type="range" min="1" max="100" value="1">
2023-03-29 02:37:31 +02:00
</div>
2023-04-01 19:41:32 +02:00
<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>
</form>
<div class="mb-3">
<label for="padding">Sats in inscription (padding)</label>
<input style="width: 25%" id="padding" type="text" value=""/>
</div>
</div>
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
<div style="margin-top: 20px; margin-bottom: 20px;">
<button class="submit btn btn-primary">Submit</button>
<button style="display:none;" class="startover btn btn-primary">Reset</button>
</div>
<div class="display"></div>
<div style="display: none;" class="file"></div>
2023-03-29 02:37:31 +02:00
<script>
// adjust for your needs
let padding = 10000; // default padding as of ord native wallet
let encodedAddressPrefix = 'bc'; // mainnet: 'bc', signet/testnet: 'tb'
2023-04-01 19:41:32 +02:00
let mempoolNetwork = 'signet/'; // mainnet: '', 'signet/', 'testnet/'
2023-03-29 02:37:31 +02:00
// no changes from here
2023-04-01 19:41:32 +02:00
const privkey = bytesToHex(cryptoUtils.Noble.utils.randomPrivateKey());
2023-03-29 02:37:31 +02:00
let pushing = false;
let files = [];
sessionStorage.clear();
2023-04-01 19:41:32 +02:00
window.onload = function () {
2023-03-29 02:37:31 +02:00
$('#padding').value = padding;
2023-04-01 19:41:32 +02:00
$('.upload_file').onclick = showUploader;
$('.registration').onclick = showRegister;
$('.brc20_mint').onclick = showBrc20Mint;
$('.brc20_deploy').onclick = showBrc20Deploy;
2023-03-29 02:37:31 +02:00
};
function showRegister() {
$('#padding').value = '546';
padding = '546';
2023-03-29 02:37:31 +02:00
files = [];
$('#app-form').reset();
2023-04-01 19:41:32 +02:00
$('.brc20_deploy_form').style.display = "none";
$('.brc20_mint_form').style.display = "none";
$('.file_form').style.display = "none";
$('.dns_form').style.display = "block";
$('.dns_checker').style.display = "inline";
$('.dns').value = "";
2023-03-29 02:37:31 +02:00
document.getElementById('brc20_mint_nav').classList.remove('active');
document.getElementById('brc20_deploy_nav').classList.remove('active');
document.getElementById('upload_file_nav').classList.remove('active');
document.getElementById('registration_nav').classList.add('active');
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
function showUploader() {
$('#padding').value = '10000';
padding = '10000';
2023-03-29 02:37:31 +02:00
files = [];
$('#app-form').reset();
2023-04-01 19:41:32 +02:00
$('.brc20_deploy_form').style.display = "none";
$('.brc20_mint_form').style.display = "none";
$('.file_form').style.display = "block";
$('.dns_form').style.display = "none";
$('.dns_checker').style.display = "none";
2023-03-29 02:37:31 +02:00
document.getElementById('brc20_mint_nav').classList.remove('active');
document.getElementById('brc20_deploy_nav').classList.remove('active');
document.getElementById('upload_file_nav').classList.add('active');
document.getElementById('registration_nav').classList.remove('active');
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
function showBrc20Deploy() {
$('#padding').value = '546';
padding = '546';
2023-03-29 02:37:31 +02:00
files = [];
$('#app-form').reset();
2023-04-01 19:41:32 +02:00
$('.brc20_deploy_form').style.display = "block";
$('.brc20_mint_form').style.display = "none";
$('.file_form').style.display = "none";
$('.dns_form').style.display = "none";
$('.dns_checker').style.display = "none";
$('.registration').onclick = showRegister;
2023-03-29 02:37:31 +02:00
document.getElementById('brc20_mint_nav').classList.remove('active');
document.getElementById('brc20_deploy_nav').classList.add('active');
document.getElementById('upload_file_nav').classList.remove('active');
document.getElementById('registration_nav').classList.remove('active');
}
function showBrc20Mint() {
$('#padding').value = '546';
padding = '546';
2023-03-29 02:37:31 +02:00
files = [];
$('#app-form').reset();
2023-04-01 19:41:32 +02:00
$('.brc20_deploy_form').style.display = "none";
$('.brc20_mint_form').style.display = "block";
$('.file_form').style.display = "none";
$('.dns_form').style.display = "none";
$('.dns_checker').style.display = "none";
$('.registration').onclick = showRegister;
2023-03-29 02:37:31 +02:00
document.getElementById('brc20_mint_nav').classList.add('active');
document.getElementById('brc20_deploy_nav').classList.remove('active');
document.getElementById('upload_file_nav').classList.remove('active');
document.getElementById('registration_nav').classList.remove('active');
}
showUploader();
2023-04-01 19:41:32 +02:00
$('.form').addEventListener("change", async function () {
2023-03-29 02:37:31 +02:00
files = [];
let limit_reached = 0;
2023-04-01 19:41:32 +02:00
for (let i = 0; i < this.files.length; i++) {
2023-03-29 02:37:31 +02:00
let b64;
let mimetype = this.files[i].type;
2023-04-01 19:41:32 +02:00
if (mimetype.includes("text/plain")) {
2023-03-29 02:37:31 +02:00
mimetype += ";charset=utf-8";
2023-03-16 12:33:19 -05:00
}
2023-03-29 02:37:31 +02:00
if (this.files[i].size >= 350000) {
limit_reached += 1;
} else {
2023-04-01 19:41:32 +02:00
b64 = await encodeBase64(this.files[i]);
let base64 = b64.substring(b64.indexOf("base64,") + 7);
let hex = base64ToHex(base64);
2023-03-29 02:37:31 +02:00
//console.log( "hex:", hex );
//console.log( "bytes:", hexToBytes( hex ) );
let sha256 = await fileToSha256Hex(this.files[i]);
2023-04-01 19:41:32 +02:00
files.push({name: this.files[i].name, hex: hex, mimetype: mimetype, sha256: sha256.replace('0x', '')});
2023-03-16 12:33:19 -05:00
}
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
if (limit_reached != 0) {
alert(limit_reached + " of your desired inscriptions exceed(s) the maximum of 350kb.")
2023-03-29 02:37:31 +02:00
}
console.log(files);
});
2023-04-01 19:41:32 +02:00
$('.startover').addEventListener("click", async function () {
2023-03-29 02:37:31 +02:00
location.reload();
});
2023-04-01 19:41:32 +02:00
$('.submit').addEventListener("click", async function () {
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
if (!isValidAddress()) {
2023-03-29 02:37:31 +02:00
alert('Invalid taproot address.');
return;
}
2023-04-01 19:41:32 +02:00
if ($('.brc20_deploy_form').style.display != "none") {
2023-03-29 02:37:31 +02:00
files = [];
let deploy = '{ \n' +
' "p": "brc-20",\n' +
' "op": "deploy",\n' +
' "tick": "",\n' +
' "max": "",\n' +
' "lim": ""\n' +
'}';
2023-04-01 19:41:32 +02:00
if (isNaN(parseInt($('#brc20-deploy-max').value))) {
2023-03-29 02:37:31 +02:00
alert('Invalid supply.');
2023-03-14 10:27:09 -05:00
return;
}
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
if (isNaN(parseInt($('#brc20-deploy-lim').value))) {
2023-03-29 02:37:31 +02:00
alert('Invalid limit.');
return;
2023-03-14 10:27:09 -05:00
}
2023-04-01 19:41:32 +02:00
if ($('#brc20-deploy-ticker').value == '' || $('#brc20-deploy-ticker').value.length != 4) {
2023-03-29 02:37:31 +02:00
alert('Invalid ticker length. Must be 4 characters.');
return;
}
deploy = JSON.parse(deploy);
deploy.tick = $('#brc20-deploy-ticker').value;
deploy.max = $('#brc20-deploy-max').value;
deploy.lim = $('#brc20-deploy-lim').value;
let mimetype = "text/plain;charset=utf-8";
2023-04-01 19:41:32 +02:00
files.push({name: deploy.tick, hex: textToHex(JSON.stringify(deploy)), mimetype: mimetype, sha256: ''});
2023-03-29 02:37:31 +02:00
console.log(files);
}
2023-04-01 19:41:32 +02:00
if ($('.brc20_mint_form').style.display != "none") {
2023-03-29 02:37:31 +02:00
files = [];
let mint = '{ \n' +
' "p": "brc-20",\n' +
' "op": "mint",\n' +
' "tick": "",\n' +
' "amt": ""\n' +
'}';
2023-04-01 19:41:32 +02:00
if (isNaN(parseInt($('#brc20-mint-amount').value))) {
2023-03-29 02:37:31 +02:00
alert('Invalid mint amount.');
return;
}
2023-04-01 19:41:32 +02:00
if ($('#brc20-mint-ticker').value == '' || $('#brc20-mint-ticker').value.length != 4) {
2023-03-29 02:37:31 +02:00
alert('Invalid ticker length. Must be 4 characters.');
return;
}
mint = JSON.parse(mint);
mint.tick = $('#brc20-mint-ticker').value;
mint.amt = $('#brc20-mint-amount').value;
let repeat = parseInt($('#brc20-mint-repeat').value);
2023-04-01 19:41:32 +02:00
if (isNaN(repeat)) {
2023-03-29 02:37:31 +02:00
alert('Invalid repeat amount.');
return;
}
2023-04-01 19:41:32 +02:00
for (let i = 0; i < repeat; i++) {
2023-03-29 02:37:31 +02:00
let mimetype = "text/plain;charset=utf-8";
2023-04-01 19:41:32 +02:00
files.push({
name: mint.tick + '_' + i,
hex: textToHex(JSON.stringify(mint)),
mimetype: mimetype,
sha256: ''
});
2023-03-29 02:37:31 +02:00
}
console.log(files);
}
2023-04-01 19:41:32 +02:00
if ($('.dns_form').style.display != "none") {
2023-03-29 02:37:31 +02:00
files = [];
2023-04-01 19:41:32 +02:00
let sats_domains = $('.dns').value.split("\n");
2023-03-29 02:37:31 +02:00
let sats_domains_cleaned = [];
2023-04-01 19:41:32 +02:00
for (let sats_domain in sats_domains) {
2023-03-29 02:37:31 +02:00
let domain = sats_domains[sats_domain].trim();
if (domain == '' || sats_domains_cleaned.includes(domain)) {
continue;
}
sats_domains_cleaned.push(domain);
}
2023-04-01 19:41:32 +02:00
for (let sats_domain in sats_domains_cleaned) {
2023-03-29 02:37:31 +02:00
let mimetype = "text/plain;charset=utf-8";
2023-04-01 19:41:32 +02:00
let domain = {"p": "sns", "op": "reg", "name": sats_domains_cleaned[sats_domain].trim()};
files.push({
name: sats_domains_cleaned[sats_domain].trim(),
hex: textToHex(JSON.stringify(domain)),
mimetype: mimetype,
sha256: ''
});
2023-03-29 02:37:31 +02:00
console.log(domain);
}
}
2023-04-01 19:41:32 +02:00
if (files.length == 0) {
2023-03-29 02:37:31 +02:00
alert('Nothing to inscribe. Please upload some files or use one of the additional options.');
return;
}
let _padding = parseInt($('#padding').value);
2023-04-01 19:41:32 +02:00
if (!isNaN(_padding) && _padding <= Number.MAX_SAFE_INTEGER && _padding >= 1) {
2023-03-29 02:37:31 +02:00
padding = _padding;
2023-04-01 19:41:32 +02:00
} else {
2023-03-29 02:37:31 +02:00
alert('Invalid padding. Please enter a sats amount for each inscription.');
return;
}
2023-04-01 19:41:32 +02:00
$('.submit').style.display = "none";
$('.startover').style.display = "inline-block";
2023-03-29 02:37:31 +02:00
const KeyPair = cryptoUtils.KeyPair;
const seckey = new KeyPair(privkey);
2023-04-01 19:41:32 +02:00
const pubkey = seckey.pub.rawX;
2023-03-29 02:37:31 +02:00
const ec = new TextEncoder();
const init_script = [
pubkey,
'OP_CHECKSIG'
];
2023-04-01 19:41:32 +02:00
const init_leaf = await BTON.Tap.getLeaf(BTON.Script.encode(init_script));
const [init_tapkey] = await BTON.Tap.getPubkey(pubkey, [init_leaf]);
const init_cblock = await BTON.Tap.getPath(pubkey, init_leaf);
2023-03-29 02:37:31 +02:00
let inscriptions = [];
let total_fee = 0;
let feerate = await getMinFeeRate();
2023-04-01 19:41:32 +02:00
sessionStorage["determined_feerate"] = sessionStorage["feerate"];
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
if (sessionStorage["feerate"]) {
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
feerate = Number(sessionStorage["feerate"]);
sessionStorage["determined_feerate"] = sessionStorage["feerate"];
2023-03-29 02:37:31 +02:00
}
let base_size = 160;
2023-04-01 19:41:32 +02:00
for (let i = 0; i < files.length; i++) {
2023-03-29 02:37:31 +02:00
const hex = files[i].hex;
2023-04-01 19:41:32 +02:00
const data = hexToBytes(hex);
const mimetype = ec.encode(files[i].mimetype);
2023-03-29 02:37:31 +02:00
const script = [
pubkey,
'OP_CHECKSIG',
'OP_0',
'OP_IF',
ec.encode('ord'),
'01',
mimetype,
'OP_0',
data,
'OP_ENDIF'
];
2023-04-01 19:41:32 +02:00
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);
let inscriptionAddress = BTON.Tap.encodeAddress(tapkey, encodedAddressPrefix);
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
console.log('Inscription address: ', inscriptionAddress);
2023-03-29 02:37:31 +02:00
console.log('Tapkey:', tapkey);
let txsize = 600 + Math.floor(data.length / 4);
if(files[i].sha256 == '')
{
base_size = Math.floor(data.length / 4) * i;
txsize = 200 + Math.floor(data.length / 4);
}
2023-03-29 02:37:31 +02:00
console.log("TXSIZE", txsize);
2023-03-29 02:37:31 +02:00
let fee = feerate * txsize;
total_fee += fee;
inscriptions.push(
{
leaf: leaf,
2023-04-01 19:41:32 +02:00
tapkey: tapkey,
cblock: cblock,
inscriptionAddress: inscriptionAddress,
txsize: txsize,
fee: fee,
script: script
2023-03-29 02:37:31 +02:00
}
);
}
2023-04-01 19:41:32 +02:00
let fundingAddress = BTON.Tap.encodeAddress(init_tapkey, encodedAddressPrefix);
console.log('Funding address: ', fundingAddress);
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
let toAddress = $('.address').value;
console.log('Address that will receive the inscription:', toAddress);
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
let decodedToAddress = "5120" + BTON.Tap.decodeAddress(toAddress).hex;
console.log('To address decoded:', decodedToAddress);
2023-03-29 02:37:31 +02:00
let total_fees = 550 + (base_size * inscriptions.length) + total_fee + (padding * inscriptions.length);
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
let sats_price = await satsToDollars(total_fees);
sats_price = Math.floor(sats_price * 100) / 100;
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
let html = `<p>Please send at least <strong>${total_fees} sats</strong> ($${sats_price}) to the address below (click to copy). Once you sent the amount, do NOT close this window!</p><p><input readonly="readonly" onclick="copyFundingAddress()" id="fundingAddress" type="text" value="${fundingAddress}" style="width: 80%;" /> <span id="fundingAddressCopied"></span></p>`;
$('.display').innerHTML = html;
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
let qr_value = "bitcoin:" + fundingAddress + "?amount=" + satsToBitcoin(total_fees);
console.log("qr:", qr_value);
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
$('.display').append(createQR(qr_value));
$('.display').innerHTML += `<p class="checking_mempool">Checking the mempool<span class="dots">.</span></p>`;
$('.display').innerHTML += '<p>' + (padding * inscriptions.length) + ` sats will go to the address</p><p>${total_fee} sats will go to miners as a mining fee</p>`;
$('.display').style.display = "block";
2023-03-29 02:37:31 +02:00
$('#setup').style.display = "none";
2023-04-01 19:41:32 +02:00
await loopTilAddressReceivesMoney(fundingAddress, true);
await waitSomeSeconds(2);
let txinfo = await addressReceivedMoneyInThisTx(fundingAddress);
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
let txid = txinfo[0];
let vout = txinfo[1];
let amt = txinfo[2];
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
console.log("yay! txid:", txid, "vout:", vout, "amount:", amt);
2023-03-29 02:37:31 +02:00
$('.modal-content').innerHTML = '<div id="funds-msg">Funds are on the way. Please wait...</div>';
2023-04-01 19:41:32 +02:00
$('.modal').style.display = "block";
2023-03-29 02:37:31 +02:00
let outputs = [];
2023-04-01 19:41:32 +02:00
for (let i = 0; i < inscriptions.length; i++) {
2023-03-29 02:37:31 +02:00
outputs.push(
{
value: padding + inscriptions[i].fee,
scriptPubKey: '5120' + inscriptions[i].tapkey
}
);
}
const init_redeemtx = {
version: 2,
input: [{
txid: txid,
vout: vout,
2023-04-01 19:41:32 +02:00
prevout: {value: amt, scriptPubKey: '5120' + init_tapkey},
2023-03-29 02:37:31 +02:00
witness: []
}],
output: outputs,
locktime: 0
};
2023-04-01 19:41:32 +02:00
const init_sig = await BTON.Sig.taproot.sign(seckey.raw, init_redeemtx, 0, {extention: init_leaf});
init_redeemtx.input[0].witness = [init_sig, init_script, init_cblock];
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
console.dir(init_redeemtx, {depth: null});
console.log('YOUR SECKEY', seckey);
2023-03-29 02:37:31 +02:00
let rawtx = BTON.Tx.encode(init_redeemtx);
2023-04-01 19:41:32 +02:00
let _txid = await pushBTCpmt(rawtx);
2023-03-29 02:37:31 +02:00
console.log('Init TX', _txid);
let include_mempool = true;
2023-03-29 07:12:08 +02:00
2023-04-01 19:41:32 +02:00
async function inscribe(inscription, vout) {
2023-03-29 02:37:31 +02:00
2023-03-29 07:12:08 +02:00
// we are running into an issue with 25 child transactions for unconfirmed parents.
// so once the limit is reached, we wait for the parent tx to confirm.
await loopTilAddressReceivesMoney(inscription.inscriptionAddress, include_mempool);
2023-04-01 19:41:32 +02:00
await waitSomeSeconds(2);
let txinfo2 = await addressReceivedMoneyInThisTx(inscription.inscriptionAddress);
2023-03-29 02:37:31 +02:00
document.getElementById('modal-reset').style.display = 'block';
document.getElementById('funds-msg').style.display = 'none';
2023-04-01 19:41:32 +02:00
let txid2 = txinfo2[0];
let amt2 = txinfo2[2];
2023-03-29 02:37:31 +02:00
const redeemtx = {
version: 2,
input: [{
txid: txid2,
vout: vout,
2023-04-01 19:41:32 +02:00
prevout: {value: amt2, scriptPubKey: '5120' + inscription.tapkey},
2023-03-29 02:37:31 +02:00
witness: []
}],
2023-04-01 19:41:32 +02:00
output: [{
2023-03-29 02:37:31 +02:00
value: amt2 - inscription.fee,
scriptPubKey: decodedToAddress
}],
locktime: 0
};
2023-04-01 19:41:32 +02:00
const sig = await BTON.Sig.taproot.sign(seckey.raw, redeemtx, 0, {extention: inscription.leaf});
redeemtx.input[0].witness = [sig, inscription.script, inscription.cblock];
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
console.dir(redeemtx, {depth: null});
2023-03-29 02:37:31 +02:00
let rawtx2 = BTON.Tx.encode(redeemtx);
2023-03-29 12:42:25 +02:00
let _txid2;
2023-03-29 02:37:31 +02:00
// since we don't know any mempool space api rate limits, we will be careful with spamming
await isPushing();
pushing = true;
_txid2 = await pushBTCpmt( rawtx2 );
2023-03-29 02:37:31 +02:00
await sleep(1000);
pushing = false;
if(_txid2.includes('descendant'))
{
include_mempool = false;
inscribe(inscription, vout);
$('#descendants-warning').style.display = 'inline-block';
return;
}
2023-04-01 19:41:32 +02:00
try {
2023-03-29 02:37:31 +02:00
JSON.parse(_txid2);
let html = `<p style="background-color: white; color: black;">Error: ${_txid2}</p>`;
html += '<hr/>';
2023-04-01 19:41:32 +02:00
$('.modal').innerHTML += html;
} catch (e) {
2023-03-29 02:37:31 +02:00
let html = `<p style="background-color: white; color: black;">Inscription #${vout} transaction:</p><p style="word-wrap: break-word;"><a href="https://mempool.space/${mempoolNetwork}tx/${_txid2}" target="_blank">https://mempool.space/${mempoolNetwork}tx/${_txid2}</a></p>`;
html += `<p style="background-color: white; color: black;">Ordinals explorer (after tx confirmation):</p><p style="word-wrap: break-word;"><a href="https://ordinals.com/inscription/${_txid2}i0" target="_blank">https://ordinals.com/inscription/${_txid2}i0</a></p>`;
html += '<hr/>';
2023-04-01 19:41:32 +02:00
$('.modal-content').innerHTML += html;
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
$('.modal').style.display = "block";
$('.black-bg').style.display = "block";
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
for (let i = 0; i < inscriptions.length; i++) {
2023-03-29 02:37:31 +02:00
inscribe(inscriptions[i], i);
}
});
function arrayBufferToBuffer(ab) {
var buffer = new buf.Buffer(ab.byteLength)
var view = new Uint8Array(ab)
for (var i = 0; i < buffer.length; ++i) {
buffer[i] = view[i]
}
return buffer
}
function hexString(buffer) {
const byteArray = new Uint8Array(buffer)
const hexCodes = [...byteArray].map(value => {
return value.toString(16).padStart(2, '0')
})
2023-04-01 19:41:32 +02:00
return '0x' + hexCodes.join('')
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
async function fileToArrayBuffer(file) {
2023-03-29 02:37:31 +02:00
return new Promise(function (resolve, reject) {
const reader = new FileReader()
2023-04-01 19:41:32 +02:00
const readFile = function (event) {
2023-03-29 02:37:31 +02:00
const buffer = reader.result
resolve(buffer)
}
reader.addEventListener('load', readFile)
reader.readAsArrayBuffer(file)
})
}
2023-04-01 19:41:32 +02:00
async function bufferToSha256(buffer) {
2023-03-29 02:37:31 +02:00
return window.crypto.subtle.digest('SHA-256', buffer)
}
2023-04-01 19:41:32 +02:00
async function fileToSha256Hex(file) {
2023-03-29 02:37:31 +02:00
const buffer = await fileToArrayBuffer(file)
const hash = await bufferToSha256(arrayBufferToBuffer(buffer))
return hexString(hash)
}
function copyFundingAddress() {
let copyText = document.getElementById("fundingAddress");
copyText.select();
copyText.setSelectionRange(0, 99999);
navigator.clipboard.writeText(copyText.value);
document.getElementById("fundingAddressCopied").innerHTML = ' Copied!';
2023-04-01 19:41:32 +02:00
setTimeout(function () {
2023-03-29 02:37:31 +02:00
document.getElementById("fundingAddressCopied").innerHTML = '';
}, 5000);
}
2023-04-01 19:41:32 +02:00
async function isPushing() {
while (pushing) {
2023-03-29 02:37:31 +02:00
await sleep(10);
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getMaxFeeRate() {
2023-04-01 19:41:32 +02:00
let fees = await getData("https://mempool.space/" + mempoolNetwork + "api/v1/fees/recommended");
fees = JSON.parse(fees);
2023-03-29 02:37:31 +02:00
// if ( !( "minimumFee" in fees ) ) return "error -- site down";
// var minfee = fees[ "minimumFee" ];
2023-04-01 19:41:32 +02:00
if (!("fastestFee" in fees)) return "error -- site down";
let maxfee = fees["fastestFee"];
2023-03-29 02:37:31 +02:00
return maxfee;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
async function getMinFeeRate() {
2023-04-01 19:41:32 +02:00
let fees = await getData("https://mempool.space/" + mempoolNetwork + "api/v1/fees/recommended");
fees = JSON.parse(fees);
if (!("minimumFee" in fees)) return "error -- site down";
let minfee = fees["minimumFee"];
2023-03-29 02:37:31 +02:00
// if ( !( "fastestFee" in fees ) ) return "error -- site down";
// var maxfee = fees[ "fastestFee" ];
return minfee;
}
2023-04-01 19:41:32 +02:00
function isValidTaprootAddress(address) {
2023-03-29 02:37:31 +02:00
try {
2023-04-01 19:41:32 +02:00
BTON.Tap.decodeAddress(address).hex;
2023-03-29 02:37:31 +02:00
return true;
2023-04-01 19:41:32 +02:00
} catch (e) {
}
2023-03-29 02:37:31 +02:00
return;
}
2023-04-01 19:41:32 +02:00
function isValidJson(content) {
if (!content) return;
2023-03-29 02:37:31 +02:00
try {
2023-04-01 19:41:32 +02:00
var json = JSON.parse(content);
} catch (e) {
2023-03-29 02:37:31 +02:00
return;
}
return true;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
async function getAllFeeRates() {
2023-04-01 19:41:32 +02:00
let fees = await getData("https://mempool.space/" + mempoolNetwork + "api/v1/fees/recommended");
fees = JSON.parse(fees);
2023-03-29 02:37:31 +02:00
return fees;
}
2023-04-01 19:41:32 +02:00
function getData(url) {
return new Promise(async function (resolve, reject) {
function inner_get(url) {
2023-03-29 02:37:31 +02:00
let xhttp = new XMLHttpRequest();
2023-04-01 19:41:32 +02:00
xhttp.open("GET", url, true);
2023-03-29 02:37:31 +02:00
xhttp.send();
return xhttp;
}
2023-04-01 19:41:32 +02:00
let data = inner_get(url);
data.onerror = function (e) {
resolve("error");
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
async function isResponseReady() {
2023-04-01 19:41:32 +02:00
return new Promise(function (resolve2, reject) {
if (!data.responseText || data.readyState != 4) {
setTimeout(async function () {
2023-03-29 02:37:31 +02:00
let msg = await isResponseReady();
2023-04-01 19:41:32 +02:00
resolve2(msg);
}, 1);
2023-03-29 02:37:31 +02:00
} else {
2023-04-01 19:41:32 +02:00
resolve2(data.responseText);
2023-03-29 02:37:31 +02:00
}
});
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
let returnable = await isResponseReady();
2023-04-01 19:41:32 +02:00
resolve(returnable);
2023-03-29 02:37:31 +02:00
});
}
2023-04-01 19:41:32 +02:00
async function pushBTCpmt(rawtx) {
let txid = await postData("https://mempool.space/" + mempoolNetwork + "api/tx", rawtx);
2023-03-29 02:37:31 +02:00
return txid;
}
2023-04-01 19:41:32 +02:00
function waitSomeSeconds(number) {
2023-03-29 02:37:31 +02:00
let num = number.toString() + "000";
2023-04-01 19:41:32 +02:00
num = Number(num);
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("");
}, num);
2023-03-29 02:37:31 +02:00
});
}
2023-04-01 19:41:32 +02:00
async function postData(url, json, content_type = "", apikey = "") {
2023-03-29 02:37:31 +02:00
let rtext = "";
2023-04-01 19:41:32 +02:00
function inner_post(url, json, content_type = "", apikey = "") {
2023-03-29 02:37:31 +02:00
let xhttp = new XMLHttpRequest();
2023-04-01 19:41:32 +02:00
xhttp.open("POST", url, true);
if (content_type) {
xhttp.setRequestHeader(`Content-Type`, content_type);
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
if (apikey) {
xhttp.setRequestHeader(`X-Api-Key`, apikey);
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
xhttp.send(json);
2023-03-29 02:37:31 +02:00
return xhttp;
}
2023-04-01 19:41:32 +02:00
let data = inner_post(url, json, content_type, apikey);
data.onerror = function (e) {
2023-03-29 02:37:31 +02:00
rtext = "error";
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
async function isResponseReady() {
2023-04-01 19:41:32 +02:00
return new Promise(function (resolve, reject) {
if (rtext == "error") {
resolve(rtext);
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
if (!data.responseText || data.readyState != 4) {
setTimeout(async function () {
2023-03-29 02:37:31 +02:00
let msg = await isResponseReady();
2023-04-01 19:41:32 +02:00
resolve(msg);
}, 50);
2023-03-29 02:37:31 +02:00
} else {
2023-04-01 19:41:32 +02:00
resolve(data.responseText);
2023-03-29 02:37:31 +02:00
}
});
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
let returnable = await isResponseReady();
return returnable;
}
2023-04-01 19:41:32 +02:00
async function loopTilAddressReceivesMoney(address, includeMempool) {
2023-03-29 02:37:31 +02:00
let itReceivedMoney = false;
2023-04-01 19:41:32 +02:00
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...");
try {
itReceivedMoney = await addressOnceHadMoney(address, includeMempool);
}catch(e){ }
2023-04-01 19:41:32 +02:00
let msg = await isDataSetYet(itReceivedMoney);
resolve(msg);
}, 2000);
2023-03-29 02:37:31 +02:00
} else {
2023-04-01 19:41:32 +02:00
resolve(data_i_seek);
2023-03-29 02:37:31 +02:00
}
});
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
async function getTimeoutData() {
2023-04-01 19:41:32 +02:00
let data_i_seek = await isDataSetYet(itReceivedMoney);
2023-03-29 02:37:31 +02:00
return data_i_seek;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
let returnable = await getTimeoutData();
return returnable;
}
2023-04-01 19:41:32 +02:00
async function addressReceivedMoneyInThisTx(address) {
2023-03-29 02:37:31 +02:00
let txid;
let vout;
let amt;
2023-04-01 19:41:32 +02:00
let nonjson = await getData("https://mempool.space/" + mempoolNetwork + "api/address/" + address + "/txs");
let json = JSON.parse(nonjson);
json.forEach(function (tx) {
tx["vout"].forEach(function (output, index) {
if (output["scriptpubkey_address"] == address) {
txid = tx["txid"];
2023-03-14 10:27:09 -05:00
vout = index;
2023-04-01 19:41:32 +02:00
amt = output["value"];
2023-03-14 10:27:09 -05:00
}
});
2023-03-29 02:37:31 +02:00
});
return [txid, vout, amt];
}
2023-04-01 19:41:32 +02:00
async function addressOnceHadMoney(address, includeMempool) {
let url = "https://mempool.space/" + mempoolNetwork + "api/address/" + address;
let nonjson = await getData(url);
if (!isValidJson(nonjson)) return false;
let json = JSON.parse(nonjson);
if (json["chain_stats"]["tx_count"] > 0 || (includeMempool && json["mempool_stats"]["tx_count"] > 0)) {
2023-03-29 02:37:31 +02:00
return true;
}
return false;
}
2023-04-01 19:41:32 +02:00
function dotLoop(string) {
if (!$('.dots')) {
setTimeout(function () {
dotLoop(string);
}, 1000);
2023-03-29 02:37:31 +02:00
return;
}
2023-04-01 19:41:32 +02:00
if (string.length < 3) {
2023-03-29 02:37:31 +02:00
string = string + ".";
} else {
string = ".";
}
2023-04-01 19:41:32 +02:00
$('.dots').innerText = string;
setTimeout(function () {
dotLoop(string);
}, 1000);
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
dotLoop(".");
function timer(num) {
if (!num) {
$('.timer').style.display = "none";
2023-03-29 02:37:31 +02:00
return;
}
num = num - 1;
2023-04-01 19:41:32 +02:00
$('.timer').innerText = num;
setTimeout(function () {
timer(num);
}, 1000);
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
function satsToBitcoin(sats) {
if (sats >= 100000000) sats = sats * 10;
let string = String(sats).padStart(8, "0").slice(0, -9) + "." + String(sats).padStart(8, "0").slice(-9);
if (string.substring(0, 1) == ".") string = "0" + string;
2023-03-29 02:37:31 +02:00
return string;
}
2023-04-01 19:41:32 +02:00
async function satsToDollars(sats) {
if (sats >= 100000000) sats = sats * 10;
let bitcoin_price = sessionStorage["bitcoin_price"];
let value_in_dollars = Number(String(sats).padStart(8, "0").slice(0, -9) + "." + String(sats).padStart(8, "0").slice(-9)) * bitcoin_price;
2023-03-29 02:37:31 +02:00
return value_in_dollars;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
function modalVanish() {
2023-04-01 19:41:32 +02:00
$(".black-bg").style.display = "none";
$(".modal").style.display = "none";
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
$$('.fee').forEach(function (item) {
item.onclick = function () {
$$('.fee .num').forEach(function (item2) {
2023-03-29 02:37:31 +02:00
item2.style.backgroundColor = "grey";
});
2023-04-01 19:41:32 +02:00
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);
2023-03-29 02:37:31 +02:00
}
});
function isValidAddress() {
2023-04-01 19:41:32 +02:00
if (!isValidTaprootAddress($('.address').value)) {
2023-03-29 02:37:31 +02:00
return false;
}
return true;
}
function checkAddress() {
2023-04-01 19:41:32 +02:00
if (!isValidAddress()) {
$('.address').style.backgroundColor = "#ff5252";
$('.address').style.border = "2px solid red";
$('.type_of_address').style.border = "1px solid white";
2023-03-29 02:37:31 +02:00
} else {
2023-04-01 19:41:32 +02:00
$('.address').style.backgroundColor = "initial";
$('.address').style.border = "1px solid white";
$('.type_of_address').style.borderStyle = "none";
2023-03-29 02:37:31 +02:00
}
}
2023-04-01 19:41:32 +02:00
$('.address').onchange = checkAddress;
$('.address').onpaste = checkAddress;
$('.address').onkeyup = checkAddress;
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
async function isUsedDomain(domain) {
let 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 null;
2023-03-29 02:37:31 +02:00
return false;
}
2023-04-01 19:41:32 +02:00
2023-03-29 02:37:31 +02:00
async function checkDomain() {
$('.dns_checker').innerHTML = 'Please wait...';
let i = 1;
let registered = [];
let rate_limited = false;
2023-04-01 19:41:32 +02:00
let sats_domains = $('.dns').value.split("\n");
2023-03-29 02:37:31 +02:00
let sats_domains_cleaned = [];
2023-04-01 19:41:32 +02:00
for (let sats_domain in sats_domains) {
2023-03-29 02:37:31 +02:00
let domain = sats_domains[sats_domain].trim();
if (domain == '' || sats_domains_cleaned.includes(domain)) {
continue;
}
sats_domains_cleaned.push(domain);
}
2023-04-01 19:41:32 +02:00
for (let sats_domain in sats_domains_cleaned) {
2023-03-29 02:37:31 +02:00
let domain = sats_domains_cleaned[sats_domain].trim();
2023-04-01 19:41:32 +02:00
$('.dns_checker').innerHTML = 'Checking...(' + i + '/' + sats_domains_cleaned.length + ')';
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
let isUsed = await isUsedDomain(domain);
2023-03-29 02:37:31 +02:00
2023-04-01 19:41:32 +02:00
if (domain && isUsed === true) {
2023-03-29 02:37:31 +02:00
registered.push(domain);
2023-04-01 19:41:32 +02:00
} else if (domain && isUsed === null) {
2023-03-29 02:37:31 +02:00
rate_limited = true;
break;
}
await sleep(1000);
i++;
}
$('.dns_checker').innerHTML = 'Check availability';
2023-04-01 19:41:32 +02:00
if (rate_limited) {
alert('Cannot check any domain availability as a rate limit occurred.');
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
if (registered.length != 0) {
alert('The domain(s) ' + registered.join(', ') + ' is/are already registered.');
} else {
2023-03-29 02:37:31 +02:00
alert('All domains are available.');
}
}
2023-04-01 19:41:32 +02:00
$('.dns_checker').onclick = checkDomain;
$('#bytes_checker').onclick = async function () {
2023-03-29 02:37:31 +02:00
$('#bytes_checker').innerHTML = 'Please wait...';
let inscribed_already = [];
let errors = [];
2023-04-01 19:41:32 +02:00
for (let i = 0; i < files.length; i++) {
$('#bytes_checker').innerHTML = 'Please wait...(' + (i + 1) + '/' + files.length + ')';
2023-03-29 02:37:31 +02:00
let hash_result = await getData('https://ordinalsbot.com/api/search?hash=' + files[i].sha256);
2023-04-01 19:41:32 +02:00
try {
2023-03-29 02:37:31 +02:00
hash_result = JSON.parse(hash_result);
2023-04-01 19:41:32 +02:00
if (hash_result.results.length != 0) {
2023-03-29 02:37:31 +02:00
inscribed_already.push(files[i].name);
2023-03-14 10:27:09 -05:00
}
2023-04-01 19:41:32 +02:00
} catch (e) {
2023-03-29 02:37:31 +02:00
errors.push(files[i].name);
2023-03-16 12:33:19 -05:00
}
2023-03-29 02:37:31 +02:00
await sleep(1000);
}
2023-04-01 19:41:32 +02:00
if (inscribed_already.length != 0) {
2023-03-29 02:37:31 +02:00
alert("The following files are inscribed already: " + inscribed_already.join(', '));
}
2023-04-01 19:41:32 +02:00
if (errors.length != 0) {
2023-03-29 02:37:31 +02:00
alert("Could not check the following files due to an error: " + inscribed_already.join(', '));
}
2023-04-01 19:41:32 +02:00
if (inscribed_already.length == 0) {
2023-03-29 02:37:31 +02:00
alert("Your files seem not to be inscribed yet.");
}
$('#bytes_checker').innerHTML = 'Check if file(s) are inscribed already';
}
2023-04-01 19:41:32 +02:00
async function init(num) {
if (!num) {
2023-03-29 02:37:31 +02:00
let isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
2023-04-01 19:41:32 +02:00
if (isSafari) $('.safari_warning').style.display = "block";
2023-03-29 02:37:31 +02:00
let minfee = await getMinFeeRate();
2023-04-01 19:41:32 +02:00
$('#sats_per_byte').innerText = minfee;
$('#sats_range').value = minfee;
2023-03-29 02:37:31 +02:00
}
num = num + 1;
let allrates = await getAllFeeRates();
2023-04-01 19:41:32 +02:00
$('.minfee .num').innerText = allrates["minimumFee"];
$('.midfee .num').innerText = allrates["hourFee"];
$('.maxfee .num').innerText = allrates["fastestFee"];
2023-03-29 02:37:31 +02:00
let isgreen;
2023-04-01 19:41:32 +02:00
$$('.fee .num').forEach(function (item) {
if (item.style.backgroundColor == "green" || getComputedStyle(item).backgroundColor == "rgb(0, 128, 0)") isgreen = item;
2023-03-29 02:37:31 +02:00
});
2023-04-01 19:41:32 +02:00
if (isgreen) {
$('#sats_per_byte').innerText = Number(isgreen.innerText);
$('#sats_range').value = Number(isgreen.innerText);
sessionStorage["feerate"] = isgreen.innerText;
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
sessionStorage["bitcoin_price"] = await getBitcoinPrice();
await waitSomeSeconds(10);
init(num);
2023-03-29 02:37:31 +02:00
}
2023-04-01 19:41:32 +02:00
init(0);
2023-03-29 02:37:31 +02:00
</script>
<div class="black-bg" onclick="modalVanish();"></div>
<div class="modal">
<span id="descendants-warning" style="display:none;color:red;margin-bottom: 20px;font-size: 13px;">For the remaining inscriptions, please wait for the parent transaction to confirm. Do NOT close this window.</span>
<div class="modal-content text-truncate"></div>
2023-04-01 19:41:32 +02:00
<button id="modal-reset" class="btn btn-primary" style="margin-top: 15px; display: none;"
onclick="location.reload();">Reset
</button>
</div>
2023-03-29 02:37:31 +02:00
</body>
2023-03-14 10:27:09 -05:00
</html>