.hub and .os seeded on the chipnet TLD beacon (~2,600 sats) and added to the public registrar. .dea (already on-chain via a concurrent session) also surfaced in the TLDS array so its second-level names become registerable — consistent with the "if it's on-chain, offer it" default. portal.html: fix "t is not iterable" by passing (electrum, addresses) to BNS.getUtxosForAddresses instead of (addresses); open one BNS.connect() and share it across the UTXO scan and the buildIndex. Sign-in itself already worked (wallet unlocks, address populates) — the crash was in the subsequent names load. Ships a clearer network-blocked error too when the browser can't reach chipnet electrum ports (50004/50011/62002).
105 lines
4.8 KiB
JavaScript
105 lines
4.8 KiB
JavaScript
// One-off (idempotent): seed the chipnet TLD-certificate beacon with the
|
|
// operator-confirmed initial TLD set. Reads what's already there via the wallet's
|
|
// provider (so re-runs skip anything present), then mints a TREG for each
|
|
// missing TLD. Verifies at the end by rebuilding the snapshot from beacon
|
|
// history — the same code path the /tld-list.json endpoint uses.
|
|
//
|
|
// node src/seed-tld-beacon.mjs
|
|
//
|
|
// Design context: Decentralized.DNS/DESIGN-tld-registry.md §9 item 1. Chipnet
|
|
// only — mainnet is a separate switch and needs the TLD covenant first.
|
|
|
|
import { loadWallet } from "./lib/wallet.js";
|
|
import { registerTld, parseOpReturn } from "./lib/bns.js";
|
|
import { buildTldSnapshot } from "./lib/tld-index.js";
|
|
import { TLD_BEACON } from "./config.js";
|
|
|
|
// Operator-confirmed seed set (2026-08-20): shipped defaults minus
|
|
// deviant/bcnr/silentmode, plus x for the coinspectrum.x work already in flight.
|
|
// Extended 2026-08-29: asm, neo, gt, sc, sia, com; then dex, cex, nt; then dea.
|
|
// The operator holds the countersignature key that would otherwise gate
|
|
// ICANN-adjacent TLDs (.com, .sc, .gt, .neo) on mainnet; on chipnet no covenant
|
|
// enforces the gate, so these are seeded directly under operator authority.
|
|
// `.com` is HELD by the operator (excluded from the public registrar UI) so
|
|
// nobody else can claim names under it — the TLD cert stays on-chain, but no
|
|
// second-level registrations are offered. Future TUPD may set policy:"frozen"
|
|
// once the TLD covenant lands and enforces it.
|
|
const SEED_TLDS = [
|
|
"bch", "p2p", "bit", "nav", "test", "x",
|
|
"asm", "neo", "gt", "sc", "sia", "com",
|
|
"dex", "cex", "nt", "dea",
|
|
"hub", "os",
|
|
];
|
|
|
|
// Empty records for the seed — the TLD covenant work will populate
|
|
// policy/fee_bps/reserved later. Empty means "defaults apply everywhere",
|
|
// which per the design doc §3 is {policy:"open", fee_bps:500, min_len:1}.
|
|
const SEED_RECORDS = {};
|
|
|
|
const wallet = await loadWallet("main");
|
|
console.log(`from wallet : ${wallet.cashaddr}`);
|
|
console.log(`TLD beacon : ${TLD_BEACON}`);
|
|
console.log(`target TLD set : ${SEED_TLDS.join(" ")}`);
|
|
|
|
// Fetch what's already on the beacon so re-runs skip it.
|
|
console.log("\nfetching current TLD-beacon state …");
|
|
const history = await wallet.provider.getHistory(TLD_BEACON);
|
|
const txs = new Map();
|
|
for (const { tx_hash } of history) {
|
|
try { txs.set(tx_hash, await wallet.provider.getRawTransactionObject(tx_hash)); }
|
|
catch { /* unreadable — skip */ }
|
|
}
|
|
const before = buildTldSnapshot({ history, txs });
|
|
console.log(`present : ${before.tlds.length ? before.tlds.map((t) => t.tld).join(" ") : "(none)"}`);
|
|
|
|
const existing = new Set(before.tlds.map((t) => t.tld));
|
|
const toMint = SEED_TLDS.filter((t) => !existing.has(t));
|
|
if (!toMint.length) {
|
|
console.log("\nnothing to do — all target TLDs already registered.");
|
|
process.exit(0);
|
|
}
|
|
console.log(`will register : ${toMint.join(" ")} (${toMint.length} tx)`);
|
|
|
|
const bal = await wallet.getBalance("sat");
|
|
console.log(`wallet balance : ${bal} sat`);
|
|
|
|
const results = [];
|
|
for (const tld of toMint) {
|
|
process.stdout.write(` TREG ${tld} … `);
|
|
try {
|
|
const res = await registerTld(wallet, tld, SEED_RECORDS);
|
|
results.push({ tld, ok: true, ...res });
|
|
console.log(`ok txid=${res.txid} category=${res.category?.slice(0, 16)}…`);
|
|
} catch (e) {
|
|
results.push({ tld, ok: false, error: String(e && e.message || e) });
|
|
console.log(`FAIL ${e && e.message || e}`);
|
|
}
|
|
// A short pause so a chain query between two REGs sees the previous tx.
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
}
|
|
|
|
const failed = results.filter((r) => !r.ok);
|
|
console.log(`\n${results.length - failed.length}/${results.length} TREG(s) broadcast${failed.length ? ` (${failed.length} failed)` : ""}`);
|
|
|
|
// Verify by rebuilding the snapshot from the beacon.
|
|
console.log("\nverifying via TLD-beacon snapshot rebuild …");
|
|
await new Promise((r) => setTimeout(r, 2000)); // mempool propagation
|
|
const historyAfter = await wallet.provider.getHistory(TLD_BEACON);
|
|
const txsAfter = new Map();
|
|
for (const { tx_hash } of historyAfter) {
|
|
try { txsAfter.set(tx_hash, await wallet.provider.getRawTransactionObject(tx_hash)); }
|
|
catch { /* skip */ }
|
|
}
|
|
const after = buildTldSnapshot({ history: historyAfter, txs: txsAfter });
|
|
console.log(`snapshot root : ${after.root}`);
|
|
console.log(`snapshot tlds :`);
|
|
for (const t of after.tlds) {
|
|
console.log(` - ${t.tld.padEnd(6)} cat=${t.category.slice(0, 16)}… regHeight=${t.regHeight ?? "(mempool)"} txid=${t.regTxid.slice(0, 16)}…`);
|
|
}
|
|
const missing = SEED_TLDS.filter((t) => !after.tlds.some((s) => s.tld === t));
|
|
if (missing.length) {
|
|
console.log(`\nWARNING: still missing after broadcast: ${missing.join(" ")}`);
|
|
process.exit(1);
|
|
}
|
|
console.log(`\ndone — all ${SEED_TLDS.length} target TLDs present on the TLD beacon.`);
|
|
process.exit(0);
|