Ariadne's resolver copy and the Android indexer still admitted every REG under a cosign or hidden TLD, so they disagreed with the gateway and Theseus about which names exist. Ariadne now carries the current Argus resolver-web.js verbatim (the copy had drifted: no TLD beacon, no owner tracking, old electrum list); its daemon only imports buildIndex and normalizeName, both unchanged. Bns.java gains the same rule in Java: walk the TLD beacon, keep each TLD's TUPD policy timeline, and drop a REG whose TLD required a co-signature at that height unless the transaction re-issues the TLD certificate. If the TLD beacon cannot be read the mobile index degrades open rather than empty. Needs an APK build (0.19) and an Ariadne zip rebuild to reach devices. Dashboard balance: it was read once from the gateway at sign-in and never again, so payments and spends never showed. The sidebar and Settings figures now come straight from electrum every 15 seconds while the tab is visible, after every broadcast the page makes, on tab focus and on a new refresh button; unconfirmed coins count as spendable (listunspent includes the mempool) with a small "incl. N sat unconfirmed" line. The header wallet pill asks the dashboard for a fresh figure when opened, and the register flow keeps its stored figure current while it watches for funding.
313 lines
16 KiB
HTML
313 lines
16 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Register a TLD — Sirius.X</title>
|
||
<meta name="description" content="Mint a top-level domain on Bitcoin Cash. Any wallet can register a TLD; second-level names can then be sold under it.">
|
||
<link rel="icon" href="./assets/favicon.svg" type="image/svg+xml">
|
||
<link rel="mask-icon" href="./assets/favicon.svg" color="#d6ff3d">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:site_name" content="Sirius.X">
|
||
<meta property="og:title" content="Register a TLD on Bitcoin Cash">
|
||
<meta property="og:description" content="Mint a TLD certificate. One BCH transaction, no registrar. Renewals are per-TLD policy.">
|
||
<meta property="og:url" content="https://silentmode.st/sirius-x/tld.html">
|
||
<meta property="og:image" content="https://silentmode.st/sirius-x/brand/banner.svg">
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,400;9..144,500;9..144,600;9..144,700&family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Ubuntu:wght@400;500;700&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{
|
||
--bg:#050810; --panel:#141a24; --panel2:#0a0f1c; --line:rgba(255,255,255,.06);
|
||
--sky-mid:#0a0f1c; --sky-rim:#131a2a;
|
||
--ink:#f1f4fa; --mut:#b8c2d4; --dim:#6a7488; --acid:#d6ff3d;
|
||
--chain-native:#0AC18E;
|
||
--ok:#4fd1a5; --taken:#f6768a; --warn:#ffc75f;
|
||
--serif:'Fraunces',Georgia,serif;
|
||
--sans:'DM Sans','Inter',system-ui,sans-serif;
|
||
--mono:'JetBrains Mono',ui-monospace,monospace;
|
||
}
|
||
*{box-sizing:border-box}
|
||
html{scroll-behavior:smooth}
|
||
body{margin:0;
|
||
background:radial-gradient(ellipse 1200px 600px at 50% -5%,var(--sky-rim) 0%,transparent 60%),
|
||
radial-gradient(ellipse 900px 500px at 100% 100%,var(--sky-mid) 0%,transparent 55%),
|
||
radial-gradient(ellipse 900px 500px at 0% 100%,#0c1424 0%,transparent 55%),
|
||
var(--bg);
|
||
background-attachment:fixed;
|
||
color:var(--ink);font:16px/1.6 var(--sans);min-height:100vh;font-feature-settings:"ss01","ss02"}
|
||
h1,h2,h3{font-family:var(--serif);font-feature-settings:"ss01","ss02"}
|
||
code,.mono{font-family:var(--mono)}
|
||
html[data-font-cmp="ubuntu"] body,
|
||
html[data-font-cmp="ubuntu"] h1, html[data-font-cmp="ubuntu"] h2, html[data-font-cmp="ubuntu"] h3,
|
||
html[data-font-cmp="ubuntu"] p, html[data-font-cmp="ubuntu"] a, html[data-font-cmp="ubuntu"] button,
|
||
html[data-font-cmp="ubuntu"] span, html[data-font-cmp="ubuntu"] div,
|
||
html[data-font-cmp="ubuntu"] label, html[data-font-cmp="ubuntu"] input, html[data-font-cmp="ubuntu"] li{
|
||
font-family:'Ubuntu',system-ui,sans-serif !important
|
||
}
|
||
html[data-font-cmp="ubuntu"] code, html[data-font-cmp="ubuntu"] .mono{font-family:var(--mono) !important}
|
||
.font-picker{display:inline-flex;align-items:center;gap:2px;padding:2px;margin:0 10px;
|
||
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:999px;
|
||
font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase}
|
||
.font-picker button{background:transparent;border:none;color:var(--dim);
|
||
padding:4px 10px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:inherit;
|
||
letter-spacing:inherit;text-transform:inherit;transition:color .12s}
|
||
.font-picker button:hover{color:var(--ink)}
|
||
.font-picker button.active{background:var(--acid);color:var(--bg);font-weight:600}
|
||
a{color:var(--acid)}
|
||
.wrap{max-width:820px;margin:0 auto;padding:0 1.2rem}
|
||
.topnav{position:sticky;top:0;z-index:20;display:flex;gap:2px;align-items:center;flex-wrap:wrap;
|
||
padding:10px 1.2rem;background:rgba(11,14,20,.82);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
|
||
.topnav .brand{font-weight:600;color:var(--ink);text-decoration:none;margin-right:14px;font-size:15px;letter-spacing:.2px}
|
||
.topnav .brand .g{color:var(--acid)}
|
||
.topnav a{color:var(--mut);text-decoration:none;padding:6px 12px;border-radius:8px;font-size:14px}
|
||
.topnav a:hover{color:var(--ink);background:var(--panel)}
|
||
.topnav a.here{color:var(--acid);background:rgba(214,255,61,.08)}
|
||
.topnav a.portal{margin-left:auto;background:rgba(214,255,61,.10);color:var(--acid);font-weight:500}
|
||
.topnav a.portal:hover{background:rgba(214,255,61,.18)}
|
||
header.hero{text-align:center;padding:3.4rem 1.2rem 1rem}
|
||
.mark{font-size:44px;line-height:1}
|
||
h1{font-size:clamp(1.7rem,4.5vw,2.3rem);margin:.3rem 0 .3rem}
|
||
h1 .g{color:var(--acid)}
|
||
.tag{color:var(--mut);font-size:1rem;max-width:600px;margin:0 auto}
|
||
h2{font-size:1.25rem;margin:0 0 .4rem}
|
||
section{padding:2rem 0;border-top:1px solid var(--line);margin-top:2rem}
|
||
section:first-of-type{border-top:none;margin-top:1rem}
|
||
.btn{display:inline-block;text-decoration:none;padding:10px 18px;border-radius:10px;background:#4b7bec;color:#fff;font-size:14px;border:none;cursor:pointer;font-family:inherit}
|
||
.btn.ghost{background:transparent;border:1px solid var(--line);color:var(--ink)}
|
||
.btn.acid{background:var(--acid);color:#0b0e14;font-weight:600}
|
||
.btn:hover{filter:brightness(1.12)}
|
||
.btn:disabled{opacity:.45;cursor:not-allowed;filter:none}
|
||
.muted{color:var(--mut);font-size:13px}
|
||
.dim{color:var(--dim);font-size:12.5px}
|
||
code,.mono{background:#0e131b;border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-family:ui-monospace,monospace;font-size:13px;word-break:break-all}
|
||
.badge{display:inline-block;font-size:11px;padding:2px 10px;border-radius:999px;font-weight:600}
|
||
.b-ok{background:rgba(79,209,165,.15);color:var(--ok)}
|
||
.b-taken{background:rgba(246,118,138,.15);color:var(--taken)}
|
||
.b-check{background:rgba(139,152,169,.14);color:var(--mut)}
|
||
.status{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:10px 14px;font-size:13px;color:var(--mut);margin-top:12px}
|
||
.status.ok{border-left:3px solid var(--ok)}
|
||
.status.err{border-left:3px solid var(--taken);color:var(--taken)}
|
||
.status.warn{border-left:3px solid var(--warn);color:var(--warn)}
|
||
/* TLD search cell */
|
||
.search{max-width:600px;margin:1.5rem auto 0}
|
||
.searchrow{display:flex;gap:8px}
|
||
.searchrow input{flex:1;padding:14px 18px;font-size:17px;border-radius:12px;border:1px solid #ffffff22;background:#141a24;color:var(--ink);font-family:inherit;outline:none}
|
||
.searchrow input:focus{border-color:#4b7bec}
|
||
.searchhint{font-size:12.5px;color:var(--mut);margin-top:8px;text-align:center}
|
||
.result-card{display:grid;grid-template-columns:1fr auto auto;gap:12px;align-items:center;
|
||
background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:14px 18px;margin-top:12px}
|
||
.result-card .lbl{font-family:ui-monospace,monospace;font-size:18px;color:var(--ink)}
|
||
.result-card .lbl .dot{color:var(--acid)}
|
||
/* Registered-TLDs table */
|
||
table.tlds{width:100%;border-collapse:collapse;margin-top:1rem;font-size:13px}
|
||
table.tlds th,table.tlds td{padding:8px 12px;text-align:left;border-bottom:1px solid var(--line);vertical-align:top}
|
||
table.tlds th{color:var(--mut);font-weight:500;font-size:11.5px;text-transform:uppercase;letter-spacing:.4px}
|
||
table.tlds .tld{font-family:ui-monospace,monospace;color:var(--acid);font-size:13.5px;font-weight:600}
|
||
table.tlds .cat{font-family:ui-monospace,monospace;color:var(--mut);font-size:11.5px;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
.price, table.tlds .price{
|
||
color:var(--acid);font-family:ui-monospace,monospace;font-size:13px;font-weight:600;
|
||
padding:2px 8px;border-radius:6px;background:rgba(214,255,61,.10);white-space:nowrap;display:inline-block
|
||
}
|
||
.result-card{grid-template-columns:1fr auto auto auto !important}
|
||
footer{border-top:1px solid var(--line);padding:2rem 0 3rem;color:var(--dim);font-size:13px;text-align:center;margin-top:2.5rem}
|
||
</style>
|
||
<script type="importmap">
|
||
{ "imports": { "@bitauth/libauth": "https://silentmode.st/js/libauth.js" } }
|
||
</script>
|
||
<script src="./js/i18n.js?v=20260917i"></script>
|
||
</head>
|
||
<body>
|
||
|
||
<nav class="topnav">
|
||
<a class="brand" href="./">⭐ <span class="g">Sirius.X</span></a>
|
||
<a href="./#try">Try it</a>
|
||
<a href="./#search-input">✏️ Register</a>
|
||
<a href="./tld.html" class="here">🌐 TLD</a>
|
||
<a href="./theseus/"><svg width="14" height="14" viewBox="0 0 64 64" style="vertical-align:-2px;margin-right:4px" aria-hidden="true"><rect width="64" height="64" rx="12" fill="#0b0e14"/><path d="M32 6 L38 32 L26 32 Z" fill="#e04e4e"/><path d="M38 32 L32 58 L26 32 Z" fill="#d6ff3d"/><circle cx="32" cy="32" r="3" fill="#0b0e14"/></svg>Theseus</a>
|
||
<a href="./portal.html" class="portal">🔑 Sign in</a>
|
||
</nav>
|
||
|
||
<header class="hero">
|
||
<div class="mark">🌐</div>
|
||
<h1>Register a <span class="g">TLD</span></h1>
|
||
<p class="tag">A TLD is a certificate on the Bitcoin Cash chain. You mint it, you own it — any
|
||
second-level name registered under it lives in your TLD's registry. One BCH transaction,
|
||
no ICANN. Renewals? Your TLD, your policy.</p>
|
||
</header>
|
||
|
||
<div class="wrap">
|
||
|
||
<section id="search-section">
|
||
<h2>Search a TLD</h2>
|
||
<p class="muted">Type a label (a–z, 0–9, hyphen; up to 16 chars). Available TLDs get a Register
|
||
button that opens the shared wallet-choice modal — the same flow name registration uses.
|
||
As TLD owner you earn <b style="color:var(--ok)">90 %</b> of every name registered under
|
||
your TLD. Renewals are your call — set them per TLD, or don't.</p>
|
||
<div class="search">
|
||
<div class="searchrow">
|
||
<input id="q" placeholder="your-tld" spellcheck="false" autocomplete="off" autofocus maxlength="16">
|
||
</div>
|
||
<div class="searchhint">Register minting to your token address; you become the registry operator.</div>
|
||
</div>
|
||
<div id="result"></div>
|
||
</section>
|
||
|
||
<section id="listing">
|
||
<h2>Registered TLDs</h2>
|
||
<p class="muted">Fetched from the on-chain TLD registry via the public gateway. Refresh the page for the latest.</p>
|
||
<div id="tlds-status" class="status">Loading…</div>
|
||
<table class="tlds" id="tlds-table" style="display:none">
|
||
<thead><tr><th>TLD</th><th>Mint price</th><th>Category</th></tr></thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</section>
|
||
|
||
</div>
|
||
|
||
<footer id="site-footer"></footer>
|
||
|
||
<script>
|
||
// Simple oracle stub: static chipnet rate for testing. Same number the
|
||
// portal uses. Mainnet swaps for a real price feed.
|
||
const CHIPNET_SATS_PER_USD = 250_000;
|
||
const DEFAULT_USD = 5;
|
||
|
||
const $ = (id) => document.getElementById(id);
|
||
const esc = (s) => String(s).replace(/[&<>"']/g, (c) => ({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]));
|
||
const validLabel = (s) => /^[a-z0-9-]{1,16}$/.test(s);
|
||
const normLabel = (s) => String(s).toLowerCase().replace(/[^a-z0-9-]/g, "").slice(0, 16);
|
||
|
||
// ---------- registered-TLD list ----------
|
||
let registeredTlds = null;
|
||
async function loadTldList() {
|
||
const status = $("tlds-status"), tbody = $("tlds-table").querySelector("tbody");
|
||
try {
|
||
const r = await fetch("https://navigate.st/api/tlds");
|
||
if (!r.ok) throw new Error("api " + r.status);
|
||
const j = await r.json();
|
||
const tlds = (j.tlds || []).map((t) => (typeof t === "string" ? { tld: t } : t));
|
||
tlds.sort((a, b) => a.tld.localeCompare(b.tld));
|
||
tbody.innerHTML = tlds.map((t) => {
|
||
const p = window.siriusPricing?.priceForTld(t.tld);
|
||
const priceCell = p ? `<span class="price" title="${esc(p.tier)}">${esc(window.siriusPricing.formatUsd(p.usd))}</span>` : "—";
|
||
return `<tr>
|
||
<td class="tld">.${esc(t.tld)}</td>
|
||
<td class="price-cell">${priceCell}</td>
|
||
<td class="cat">${esc(t.certificate || t.category || "")}</td>
|
||
</tr>`;
|
||
}).join("");
|
||
$("tlds-table").style.display = "";
|
||
status.className = "status ok";
|
||
status.textContent = `${tlds.length} TLDs registered on chipnet.`;
|
||
registeredTlds = tlds.map((t) => t.tld);
|
||
refreshSearch();
|
||
} catch (e) {
|
||
status.className = "status err";
|
||
status.textContent = "Could not load TLD list: " + (e.message || e);
|
||
}
|
||
}
|
||
loadTldList();
|
||
|
||
// ---------- search result renderer ----------
|
||
function renderResult(label, state) {
|
||
const res = $("result");
|
||
if (!label) { res.innerHTML = ""; return; }
|
||
if (state === "checking") {
|
||
res.innerHTML = `<div class="result-card">
|
||
<div class="lbl"><span class="dot">.</span>${esc(label)}</div>
|
||
<span class="badge b-check">checking…</span><span></span></div>`;
|
||
return;
|
||
}
|
||
if (state === "taken") {
|
||
res.innerHTML = `<div class="result-card">
|
||
<div class="lbl"><span class="dot">.</span>${esc(label)}</div>
|
||
<span class="badge b-taken">taken</span><span></span></div>
|
||
<p class="dim" style="margin-top:8px">Someone already minted <code>.${esc(label)}</code>. Try a
|
||
different label — TLDs are first-come, first-served.</p>`;
|
||
return;
|
||
}
|
||
const p = window.siriusPricing?.priceForTld(label);
|
||
const priceBadge = p
|
||
? `<span class="price" title="${esc(p.tier)}">${esc(window.siriusPricing.formatUsd(p.usd))}</span>`
|
||
: "";
|
||
res.innerHTML = `<div class="result-card">
|
||
<div class="lbl"><span class="dot">.</span>${esc(label)}</div>
|
||
<span class="badge b-ok">available</span>
|
||
${priceBadge}
|
||
<button class="btn acid" id="go-register">Register .${esc(label)} →</button>
|
||
</div>`;
|
||
$("go-register").onclick = () => beginRegister(label);
|
||
}
|
||
|
||
// ---------- search wiring ----------
|
||
let currentLabel = "";
|
||
function refreshSearch() {
|
||
const raw = normLabel($("q").value);
|
||
currentLabel = raw;
|
||
if (!raw) { renderResult("", null); return; }
|
||
if (!validLabel(raw)) { renderResult(raw, "invalid"); return; }
|
||
if (registeredTlds !== null) {
|
||
renderResult(raw, registeredTlds.includes(raw) ? "taken" : "ok");
|
||
return;
|
||
}
|
||
renderResult(raw, "checking");
|
||
}
|
||
$("q").addEventListener("input", () => {
|
||
$("q").value = normLabel($("q").value);
|
||
refreshSearch();
|
||
});
|
||
$("q").addEventListener("keydown", (e) => {
|
||
if (e.key === "Enter" && currentLabel && registeredTlds && !registeredTlds.includes(currentLabel)) {
|
||
beginRegister(currentLabel);
|
||
}
|
||
});
|
||
|
||
// ---------- mint delegation ----------
|
||
// Register button hands the label off to the shared modal (register-flow.js
|
||
// — window.siriusRegisterTld). That modal owns the wallet-choice, fund,
|
||
// confirm, and mint steps — same UX as name registration.
|
||
function beginRegister(label) {
|
||
// Label-based tier pricing lives in siriusPricing (js/pricing.js) so
|
||
// landing / tld / mint agree. Fall back to the flat DEFAULT_USD if the
|
||
// pricing module hasn't loaded for some reason.
|
||
const p = window.siriusPricing?.priceForTld(label);
|
||
const fee = p ? p.sats : BigInt(DEFAULT_USD * CHIPNET_SATS_PER_USD);
|
||
const call = () => window.siriusRegisterTld(label, { serviceFeeSats: fee });
|
||
if (typeof window.siriusRegisterTld === "function") { call(); return; }
|
||
// Module still loading — retry until it lands.
|
||
const btn = $("go-register");
|
||
const orig = btn?.textContent;
|
||
if (btn) { btn.disabled = true; btn.textContent = "loading…"; }
|
||
const t = setInterval(() => {
|
||
if (typeof window.siriusRegisterTld === "function") {
|
||
clearInterval(t);
|
||
if (btn) { btn.disabled = false; btn.textContent = orig; }
|
||
call();
|
||
}
|
||
}, 100);
|
||
}
|
||
|
||
// ---------- ?q= deep-link (from landing links etc.) ----------
|
||
(() => {
|
||
const q = normLabel(new URLSearchParams(location.search).get("q") || "");
|
||
if (!q) return;
|
||
$("q").value = q;
|
||
const wait = setInterval(() => {
|
||
if (registeredTlds === null) return;
|
||
clearInterval(wait);
|
||
refreshSearch();
|
||
setTimeout(() => $("q").scrollIntoView({ behavior: "smooth", block: "start" }), 100);
|
||
}, 150);
|
||
})();
|
||
</script>
|
||
|
||
<script type="module" src="./js/register-flow.js?v=20260917bal"></script>
|
||
<script src="./js/pricing.js?v=20260917market"></script>
|
||
<script src="./js/session.js?v=20260917dash"></script>
|
||
<script src="./js/pin-escrow.js?v=20260909pin"></script>
|
||
<script defer src="./js/theme.js?v=20260910font"></script>
|
||
<script defer src="./js/site-footer.js?v=20260917market"></script>
|
||
<script defer src="./js/profile-menu.js?v=20260917wide"></script>
|
||
</body>
|
||
</html>
|