BNS: per-TLD on-chain registry, multi-beacon indexer, enforcement gate
Per-TLD certificates on a distinct TLD beacon supersede the legacy list-in-one-NFT
model. TLD label is the NFT commitment; TREG/TUPD payloads on the TLD beacon
mirror REG/UPD on the name beacon. Chipnet TLD beacon:
bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh
scripthash c85db10e106606273422b2733b2a6fb8b35a4d0e7dbfb20cf59bdb0833c008b8
* config.js, resolver-web.{js,d.ts} — TLD_BEACON + TLD_BEACON_SCRIPTHASH
* bns.js — KNOWN_OPS { REG, UPD, TREG, TUPD }, registerTld/updateTld/normalizeTld
* bns.js + resolver-web.js — buildIndex({enforceTld:false}) drops name REGs
whose TLD lacks a live TLD cert at their block height (mempool-friendly).
Lockstep across both files.
* lib/tld-index.js — buildTldSnapshot({history,txs}) → deterministic root over
canonicalised tlds[]. Pure, importable, and stable across insertion order.
* indexer/bns-indexer.js — BeaconIndex is multi-beacon; ws handler dispatches
by scripthash; new HTTP endpoint GET /tld-list.json + /health behind
BNS_HTTP_PORT; state file v1 → v2 migrates in fromJSON.
* publish-tld-mirror.mjs — S3 (floating + immutable content-addressed) plus
NIP-33 kind 30078 d:bns-tld-list to Nostr relays, signed via nostr-tools
(libauth's Schnorr differs from BIP-340 and relays reject it).
* seed-tld-beacon.mjs — idempotent chipnet seed. Current set on the beacon:
bch p2p bit nav test x asm neo gt sc sia com dex cex nt (15). `.com` is
held by the operator: cert on-chain, excluded from public registrar UI.
Design + docs:
* Decentralized.DNS/DESIGN-tld-registry.md — schema, enforcement,
operator-countersig gate, USD-tiered pricing floors, fee splits,
tracker/mirror mechanics, migration/grandfathering.
* INSTRUCTIONS.md §3 rewritten for the 4-step flow (TREG → UI → deploy →
republish snapshot).
* site/tlds/ — public docs page listing current TLDs + verification paths.
* site/sirius/register.html — dropdown removed; parallel search across
every TLD in the TLDS array, sorted available → taken → not-on-registry.
Config:
* ariadne.config.json tlds → [bch, p2p, bit, nav, test, x] (CA constraints;
on-chain registry is now the authoritative source, config is fallback).
* setup/install.ps1 — reads TLD list via fetchTldList (per-TLD registry)
with fallback to fetchBcnrTlds (legacy tls.bch list-NFT) then config.
Tests:
* test/tld-index.test.mjs — 30 self-contained checks (multi-beacon dispatch,
state migration, ws routing, snapshot shape + root recomputability).
* test/tld-enforcement.test.mjs — synthetic + live chipnet integration
(with-gate correctly drops all pre-seed names).
2026-08-29 17:11:02 +02:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > TLDs — the top-level domains on the Bitcoin Cash chain — Silent Mode< / title >
< meta name = "description" content = "Every BNS name lives under a top-level domain (TLD) whose certificate is itself a first-class token on the Bitcoin Cash chain. Browse the current TLDs, see how new ones are added, and verify the list against the chain." >
< link rel = "stylesheet" href = "../shared.css" >
< style >
/* Page-specific: TLD table + snapshot-verification card */
.hero{text-align:center;padding:4.5rem 1.2rem 1rem}
.mark{font-size:52px;line-height:1}
h1{font-size:clamp(1.9rem,5vw,2.7rem);margin:.4rem 0 .3rem}
h1 .g{color:var(--acid)}
.tag{color:var(--mut);font-size:1.05rem;max-width:660px;margin:0 auto}
.cta{margin-top:1.6rem;display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
.btn{display:inline-block;text-decoration:none;padding:11px 20px;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}
section{padding:2.6rem 0;border-top:1px solid var(--line);margin-top:2.5rem}
section:first-of-type{border-top:none;margin-top:1.5rem}
h2{font-size:1.4rem;margin:0 0 .4rem}
h3{font-size:1.05rem;margin:0 0 .3rem}
.lede{color:var(--mut);margin:0 0 1.5rem;max-width:720px}
ol.steps{counter-reset:s;list-style:none;padding:0;margin:1.2rem 0 0;display:grid;gap:10px}
ol.steps li{counter-increment:s;display:grid;grid-template-columns:30px 1fr;gap:14px;align-items:start;
background:var(--panel2);border:1px solid var(--line);border-radius:12px;padding:13px 16px}
ol.steps li::before{content:counter(s);grid-column:1;grid-row:1;
display:grid;place-items:center;width:24px;height:24px;border-radius:50%;
background:rgba(214,255,61,.14);color:var(--acid);font-size:12.5px;font-weight:700}
ol.steps li > *{grid-column:2;min-width:0}
ol.steps b{color:var(--ink)} ol.steps span{color:var(--mut);font-size:14px}
.note{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--acid);
border-radius:10px;padding:14px 18px;color:var(--mut);font-size:14px;margin-top:1.4rem}
.note.warn{border-left-color:var(--warn)}
.note b{color:var(--ink)}
code,.mono{background:#0e131b;border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-family:ui-monospace,monospace;font-size:13px}
pre{background:#0e131b;border:1px solid var(--line);border-radius:10px;padding:12px 14px;overflow-x:auto;
font-family:ui-monospace,monospace;font-size:13px;color:var(--ink)}
/* TLD table */
table.tlds{width:100%;border-collapse:collapse;margin-top:1.2rem;font-size:14px}
table.tlds th,table.tlds td{padding:9px 12px;text-align:left;border-bottom:1px solid var(--line)}
table.tlds th{color:var(--mut);font-weight:500;font-size:12.5px;text-transform:uppercase;letter-spacing:.4px}
table.tlds .tld{font-family:ui-monospace,monospace;color:var(--acid);font-size:15px;font-weight:600}
table.tlds .cat{font-family:ui-monospace,monospace;color:var(--mut);font-size:12px}
table.tlds .status{font-size:12px;padding:2px 10px;border-radius:999px;font-weight:600;background:rgba(79,209,165,.15);color:var(--ok)}
table.tlds .status.held{background:rgba(255,199,95,.14);color:var(--warn)}
/* verification card */
.verify{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px 18px;margin-top:1.2rem}
.verify dt{color:var(--mut);font-size:12.5px;text-transform:uppercase;letter-spacing:.3px;margin-top:10px}
.verify dt:first-of-type{margin-top:0}
.verify dd{margin:2px 0 0;font-family:ui-monospace,monospace;font-size:12.5px;word-break:break-all;color:var(--ink)}
.verify dd a{color:var(--acid);text-decoration:none;border-bottom:1px dotted var(--acid)}
footer{border-top:1px solid var(--line);padding:2.4rem 0 3.5rem;color:var(--dim);font-size:13px;text-align:center;margin-top:2.5rem}
< / style >
< / head >
< body >
< nav class = "topnav" >
< a class = "brand" href = "../" > ⛓️ Silent < span class = "g" > Mode< / span > < / a >
< a href = "../tools/" > Tools< / a >
< a href = "../prometheus/" > Prometheus< / a >
< a href = "../sirius/" > Sirius< / a >
< a href = "./" class = "here" > TLDs< / a >
2026-08-31 04:06:28 +02:00
< a href = "../hephaestus/" > Hephaestus< / a >
BNS: per-TLD on-chain registry, multi-beacon indexer, enforcement gate
Per-TLD certificates on a distinct TLD beacon supersede the legacy list-in-one-NFT
model. TLD label is the NFT commitment; TREG/TUPD payloads on the TLD beacon
mirror REG/UPD on the name beacon. Chipnet TLD beacon:
bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh
scripthash c85db10e106606273422b2733b2a6fb8b35a4d0e7dbfb20cf59bdb0833c008b8
* config.js, resolver-web.{js,d.ts} — TLD_BEACON + TLD_BEACON_SCRIPTHASH
* bns.js — KNOWN_OPS { REG, UPD, TREG, TUPD }, registerTld/updateTld/normalizeTld
* bns.js + resolver-web.js — buildIndex({enforceTld:false}) drops name REGs
whose TLD lacks a live TLD cert at their block height (mempool-friendly).
Lockstep across both files.
* lib/tld-index.js — buildTldSnapshot({history,txs}) → deterministic root over
canonicalised tlds[]. Pure, importable, and stable across insertion order.
* indexer/bns-indexer.js — BeaconIndex is multi-beacon; ws handler dispatches
by scripthash; new HTTP endpoint GET /tld-list.json + /health behind
BNS_HTTP_PORT; state file v1 → v2 migrates in fromJSON.
* publish-tld-mirror.mjs — S3 (floating + immutable content-addressed) plus
NIP-33 kind 30078 d:bns-tld-list to Nostr relays, signed via nostr-tools
(libauth's Schnorr differs from BIP-340 and relays reject it).
* seed-tld-beacon.mjs — idempotent chipnet seed. Current set on the beacon:
bch p2p bit nav test x asm neo gt sc sia com dex cex nt (15). `.com` is
held by the operator: cert on-chain, excluded from public registrar UI.
Design + docs:
* Decentralized.DNS/DESIGN-tld-registry.md — schema, enforcement,
operator-countersig gate, USD-tiered pricing floors, fee splits,
tracker/mirror mechanics, migration/grandfathering.
* INSTRUCTIONS.md §3 rewritten for the 4-step flow (TREG → UI → deploy →
republish snapshot).
* site/tlds/ — public docs page listing current TLDs + verification paths.
* site/sirius/register.html — dropdown removed; parallel search across
every TLD in the TLDS array, sorted available → taken → not-on-registry.
Config:
* ariadne.config.json tlds → [bch, p2p, bit, nav, test, x] (CA constraints;
on-chain registry is now the authoritative source, config is fallback).
* setup/install.ps1 — reads TLD list via fetchTldList (per-TLD registry)
with fallback to fetchBcnrTlds (legacy tls.bch list-NFT) then config.
Tests:
* test/tld-index.test.mjs — 30 self-contained checks (multi-beacon dispatch,
state migration, ws routing, snapshot shape + root recomputability).
* test/tld-enforcement.test.mjs — synthetic + live chipnet integration
(with-gate correctly drops all pre-seed names).
2026-08-29 17:11:02 +02:00
< a href = "../helios/" > Helios< / a >
< a href = "../hermes/" > Hermes< / a >
< / nav >
< header class = "hero" >
< div class = "mark" > 🌐< / div >
< h1 > The < span class = "g" > TLD registry< / span > < / h1 >
< p class = "tag" > Every BNS name lives under a < b > top-level domain< / b > . Under Silent
Mode's per-TLD registry, each TLD is itself a certificate on the Bitcoin
Cash chain — minted once, held in a wallet, and required to exist before
any name under it can be registered. Browse the list, see how it works,
verify it against the chain.< / p >
< div class = "cta" >
< a class = "btn acid" href = "../sirius/register.html" > Search a name →< / a >
< a class = "btn ghost" href = "#current" > See current TLDs< / a >
< / div >
< / header >
< div class = "wrap" >
< section >
< h2 > What a TLD is here< / h2 >
< p class = "lede" > A TLD (like < code > .bch< / code > , < code > .x< / code > , < code > .p2p< / code > ) is not just a
convention. Each is a CashTokens NFT with the TLD label as its commitment,
paying dust to a dedicated TLD-registry beacon on chain. That certificate
is the on-chain proof the TLD exists — and, once enforcement is on, it is
what makes any second-level name under it valid.< / p >
< ol class = "steps" >
< li > < b > Register the TLD first.< / b > < span > An operator mints the TLD certificate. Without it, names
under that TLD are not indexed by conforming resolvers.< / span > < / li >
< li > < b > Then register names under it.< / b > < span > Each name is a separate cert, minted through the
registrar (< a href = "../sirius/register.html" > sirius/register.html< / a > ), and paid by the buyer to
their own wallet.< / span > < / li >
< li > < b > Verify against the chain.< / b > < span > Anyone can walk the TLD beacon
(< code > bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh< / code > on chipnet), rebuild the list,
and compare its cryptographic root — the tracker is a cache, not authority.< / span > < / li >
< / ol >
< div class = "note" > < b > Why this exists.< / b > Without a registry, anyone could quietly declare a TLD
against the same beacon by minting a name under it. That leaves resolvers in
silent disagreement about what exists. Per-TLD certificates make the TLD set
itself something the chain records, so every resolver sees the same list.
Design: < code > Decentralized.DNS/DESIGN-tld-registry.md< / code > in the project repo.< / div >
< / section >
< section id = "current" >
< h2 > Current TLDs (chipnet)< / h2 >
2026-08-29 21:57:33 +02:00
< p class = "lede" > Fourteen TLDs are offered for public name registration on the chipnet TLD
beacon as of 2026-08-29. The live count on the chain is the authoritative source — this table
may lag by minutes until the beacon confirms.< / p >
BNS: per-TLD on-chain registry, multi-beacon indexer, enforcement gate
Per-TLD certificates on a distinct TLD beacon supersede the legacy list-in-one-NFT
model. TLD label is the NFT commitment; TREG/TUPD payloads on the TLD beacon
mirror REG/UPD on the name beacon. Chipnet TLD beacon:
bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh
scripthash c85db10e106606273422b2733b2a6fb8b35a4d0e7dbfb20cf59bdb0833c008b8
* config.js, resolver-web.{js,d.ts} — TLD_BEACON + TLD_BEACON_SCRIPTHASH
* bns.js — KNOWN_OPS { REG, UPD, TREG, TUPD }, registerTld/updateTld/normalizeTld
* bns.js + resolver-web.js — buildIndex({enforceTld:false}) drops name REGs
whose TLD lacks a live TLD cert at their block height (mempool-friendly).
Lockstep across both files.
* lib/tld-index.js — buildTldSnapshot({history,txs}) → deterministic root over
canonicalised tlds[]. Pure, importable, and stable across insertion order.
* indexer/bns-indexer.js — BeaconIndex is multi-beacon; ws handler dispatches
by scripthash; new HTTP endpoint GET /tld-list.json + /health behind
BNS_HTTP_PORT; state file v1 → v2 migrates in fromJSON.
* publish-tld-mirror.mjs — S3 (floating + immutable content-addressed) plus
NIP-33 kind 30078 d:bns-tld-list to Nostr relays, signed via nostr-tools
(libauth's Schnorr differs from BIP-340 and relays reject it).
* seed-tld-beacon.mjs — idempotent chipnet seed. Current set on the beacon:
bch p2p bit nav test x asm neo gt sc sia com dex cex nt (15). `.com` is
held by the operator: cert on-chain, excluded from public registrar UI.
Design + docs:
* Decentralized.DNS/DESIGN-tld-registry.md — schema, enforcement,
operator-countersig gate, USD-tiered pricing floors, fee splits,
tracker/mirror mechanics, migration/grandfathering.
* INSTRUCTIONS.md §3 rewritten for the 4-step flow (TREG → UI → deploy →
republish snapshot).
* site/tlds/ — public docs page listing current TLDs + verification paths.
* site/sirius/register.html — dropdown removed; parallel search across
every TLD in the TLDS array, sorted available → taken → not-on-registry.
Config:
* ariadne.config.json tlds → [bch, p2p, bit, nav, test, x] (CA constraints;
on-chain registry is now the authoritative source, config is fallback).
* setup/install.ps1 — reads TLD list via fetchTldList (per-TLD registry)
with fallback to fetchBcnrTlds (legacy tls.bch list-NFT) then config.
Tests:
* test/tld-index.test.mjs — 30 self-contained checks (multi-beacon dispatch,
state migration, ws routing, snapshot shape + root recomputability).
* test/tld-enforcement.test.mjs — synthetic + live chipnet integration
(with-gate correctly drops all pre-seed names).
2026-08-29 17:11:02 +02:00
< table class = "tlds" >
< thead > < tr > < th > TLD< / th > < th > Category (short)< / th > < th > Status< / th > < / tr > < / thead >
< tbody >
< tr > < td class = "tld" > .bch< / td > < td class = "cat" > 56253dcfbdfbeec8…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .p2p< / td > < td class = "cat" > d9b4e56d2293a4f9…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .bit< / td > < td class = "cat" > bc51b2407b13876e…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .nav< / td > < td class = "cat" > d2191a86685fa4c9…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .test< / td > < td class = "cat" > 5197632adf1f7fd3…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .x< / td > < td class = "cat" > 8dc32d8fd56f863b…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .asm< / td > < td class = "cat" > 58d3381435268faf…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .neo< / td > < td class = "cat" > a511e80816976e92…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .gt< / td > < td class = "cat" > 249a535df4633767…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .sc< / td > < td class = "cat" > f61fc465404a3eee…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .sia< / td > < td class = "cat" > 4b3fccd4076eb48c…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .dex< / td > < td class = "cat" > 9b230313b823202c…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .cex< / td > < td class = "cat" > 69fd93aedee3d353…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< tr > < td class = "tld" > .nt< / td > < td class = "cat" > 5d18221bccaab2c0…< / td > < td > < span class = "status" > public< / span > < / td > < / tr >
< / tbody >
< / table >
< / section >
< section >
< h2 > Get a name under one of these< / h2 >
< p class = "lede" > Go to < a href = "../sirius/register.html" > Sirius / register a name< / a > . Type a label — the
search fans out to every TLD in the registry in parallel and shows which
are available, which are taken, and which are held off the public
registry. Available ones mint straight into your own wallet in one
transaction; no yearly renewal.< / p >
< / section >
< section >
< h2 > How new TLDs get added< / h2 >
< p class = "lede" > On chipnet the operator's key can mint any TLD directly. On mainnet, a covenant
will enforce a countersignature from that same key on every public TLD mint
— and a USD-denominated price floor tiered by label length. This is what
keeps someone from land-grabbing every ICANN TLD in one afternoon.< / p >
< ol class = "steps" >
< li > < b > Operator TREG.< / b > < span > The operator's wallet mints the TLD certificate; the label goes
into the NFT commitment, dust flows to the TLD beacon.< / span > < / li >
< li > < b > UI opt-in.< / b > < span > The TLD is added to the registrar's list. A TLD can be minted but
intentionally omitted from the UI — the "held" pattern that keeps < code > .com< / code > off
the public registry.< / span > < / li >
< li > < b > Snapshot republish.< / b > < span > The tracker rebuilds and pushes a signed snapshot to Sia and
Nostr so downstream clients update without walking the chain themselves.< / span > < / li >
< / ol >
< div class = "note warn" > < b > Chipnet is not mainnet.< / b > The covenant that turns "operator's key" into
something enforceable is a mainnet requirement. Until it lands, treat the chipnet TLD list as an
operator-signed statement, not a decentralized fact.< / div >
< / section >
< section >
< h2 > Verify the list against the chain< / h2 >
< p class = "lede" > The tracker is a cache. The chain is the authority. Two independent paths, both public:< / p >
< h3 > Fetch the signed snapshot from Nostr< / h3 >
< p class = "lede" > Kind 30078 replaceable event, d-tag < code > bns-tld-list< / code > , signed by the
tracker's Nostr key. Any relay carries it; the event's < code > content< / code > field carries the current
snapshot root and the Sia URL where the full JSON lives.< / p >
< dl class = "verify" >
< dt > Pubkey (x-only, hex)< / dt >
< dd > f2c925194c531c7c398017e35b2396df64a61a613aa5fadebdf1f4990f2267f4< / dd >
< dt > Relays< / dt >
< dd > wss://nos.lol · wss://relay.damus.io< / dd >
< dt > Filter (nostr-tools / rust-nostr)< / dt >
< dd > { authors: [< pubkey> ], kinds: [30078], "#d": ["bns-tld-list"] }< / dd >
< / dl >
< h3 > Rebuild locally from the TLD beacon< / h3 >
< p class = "lede" > Any electrum server that indexes the chipnet chain will return the beacon's history. Recompute
the snapshot's canonical form (sort by TLD, JSON.stringify), sha256 it, compare — if the hash matches
the tracker's < code > root< / code > , the snapshot is a faithful summary of what the chain says.< / p >
< pre > cd Argus & & node --input-type=module -e "
import { loadWallet } from './src/lib/wallet.js';
import { buildTldSnapshot } from './src/lib/tld-index.js';
import { TLD_BEACON } from './src/config.js';
const w = await loadWallet('main');
const history = await w.provider.getHistory(TLD_BEACON);
const txs = new Map();
for (const {tx_hash} of history) try { txs.set(tx_hash, await w.provider.getRawTransactionObject(tx_hash)); } catch {}
console.log(buildTldSnapshot({ history, txs }));
process.exit(0);"< / pre >
< / section >
< / div >
< footer >
Silent Mode — a Deviant project · < a href = "/" > home< / a > · < a href = "/sirius/" > Sirius< / a > · < a href = "/sirius/register.html" > register a name< / a > < br >
Alpha on a test network (chipnet). You hold your own keys; verify everything against the chain.
< / footer >
< / body >
< / html >