feat(sirius-x): prices in BCH, amounts in bits, live BCH/USD rate from several exchanges
Every dollar figure on the site came from a hard-coded 250,000 sats per dollar, which implies $400 per BCH; the market is near $250, so name prices, TLD fees and sale listings were shown about 60% too cheap in dollars. The gateway now serves /api/price: the median of Coinbase, Kraken, Bitstamp, Binance and CoinGecko public tickers, no keys, cached 60 s, last good answer kept if every source fails. The site reads it first, queries the same tickers itself if the gateway is unreachable, remembers the last rate per browser, and only falls back to a constant for the very first paint. Pages repaint when the rate arrives, and the rate line says where it came from and how old it is. Units: satoshi no longer appear anywhere. Sale prices, the seller's input and the buy dialog are in BCH with the dollar figure beside them; balances, fees and dust are in bits (1 bit = 100 satoshi).
This commit is contained in:
parent
6618b38b2d
commit
b5eea9422b
15 changed files with 146 additions and 71 deletions
|
|
@ -604,9 +604,9 @@ process.exit(0);"</pre>
|
|||
|
||||
<script src="../js/session.js?v=20260917dash"></script>
|
||||
<script src="../js/pin-escrow.js?v=20260909pin"></script>
|
||||
<script src="../js/pricing.js?v=20260917market"></script>
|
||||
<script src="../js/pricing.js?v=20260920bits"></script>
|
||||
<script defer src="../js/site-footer.js?v=20260917market"></script>
|
||||
<script defer src="../js/theme.js?v=20260920compact"></script>
|
||||
<script defer src="../js/profile-menu.js?v=20260920m"></script>
|
||||
<script defer src="../js/profile-menu.js?v=20260920bits"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -564,7 +564,6 @@
|
|||
". A buyer completes it in one transaction — you are paid in the same transaction that moves the name, or not at all. No escrow, nothing to trust.": ". Ein Käufer schließt es in einer Transaktion ab — du wirst in derselben Transaktion bezahlt, die den Namen überträgt, oder gar nicht. Kein Treuhänder, nichts, dem man vertrauen muss.",
|
||||
"Checking the market…": "Markt wird geprüft…",
|
||||
"Price (USD)": "Preis (USD)",
|
||||
"Price (sat)": "Preis (Sat)",
|
||||
"List for sale →": "Zum Verkauf anbieten →",
|
||||
"Cancel listing →": "Angebot zurückziehen →",
|
||||
"Cancelling removes the offer from the market and moves your certificate once (a no-op update, a few cents), so the signed offer can never be completed later.": "Beim Zurückziehen wird das Angebot vom Markt entfernt und dein Zertifikat einmal bewegt (ein leeres Update, ein paar Cent), damit die signierte Offerte später nie mehr abgeschlossen werden kann.",
|
||||
|
|
@ -581,7 +580,6 @@
|
|||
"Request declined": "Anfrage abgelehnt",
|
||||
"Open dashboard →": "Dashboard öffnen →",
|
||||
"incl.": "inkl.",
|
||||
"sat unconfirmed · spendable now": "Sat unbestätigt · sofort verfügbar",
|
||||
"Nothing is for sale right now": "Derzeit steht nichts zum Verkauf",
|
||||
"Names go on sale when their owners list them from the dashboard. Have one to sell, or want a fresh one instead?": "Namen kommen in den Verkauf, wenn ihre Besitzer sie im Dashboard anbieten. Hast du einen zu verkaufen — oder lieber einen neuen registrieren?",
|
||||
"Sell a name from your dashboard →": "Einen Namen im Dashboard verkaufen →",
|
||||
|
|
@ -604,5 +602,7 @@
|
|||
"Restyle selection": "Auswahl umgestalten",
|
||||
"Nothing selected": "Nichts ausgewählt",
|
||||
"Undo last change": "Letzte Änderung rückgängig",
|
||||
"Stop": "Stopp"
|
||||
"Stop": "Stopp",
|
||||
"unconfirmed · spendable now": "unbestätigt · sofort verfügbar",
|
||||
"Price (BCH)": "Preis (BCH)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,7 +564,6 @@
|
|||
". A buyer completes it in one transaction — you are paid in the same transaction that moves the name, or not at all. No escrow, nothing to trust.": ". Ο αγοραστής την ολοκληρώνει σε μία συναλλαγή — πληρώνεσαι στην ίδια συναλλαγή που μεταφέρει το όνομα, ή καθόλου. Χωρίς μεσεγγύηση, τίποτα προς εμπιστοσύνη.",
|
||||
"Checking the market…": "Έλεγχος της αγοράς…",
|
||||
"Price (USD)": "Τιμή (USD)",
|
||||
"Price (sat)": "Τιμή (sat)",
|
||||
"List for sale →": "Καταχώρηση προς πώληση →",
|
||||
"Cancel listing →": "Ακύρωση αγγελίας →",
|
||||
"Cancelling removes the offer from the market and moves your certificate once (a no-op update, a few cents), so the signed offer can never be completed later.": "Η ακύρωση αφαιρεί την προσφορά από την αγορά και μετακινεί το πιστοποιητικό σου μία φορά (μια κενή ενημέρωση, λίγα λεπτά), ώστε η υπογεγραμμένη προσφορά να μην μπορεί ποτέ να ολοκληρωθεί αργότερα.",
|
||||
|
|
@ -581,7 +580,6 @@
|
|||
"Request declined": "Το αίτημα απορρίφθηκε",
|
||||
"Open dashboard →": "Άνοιγμα πίνακα ελέγχου →",
|
||||
"incl.": "συμπ.",
|
||||
"sat unconfirmed · spendable now": "sat ανεπιβεβαίωτα · διαθέσιμα τώρα",
|
||||
"Nothing is for sale right now": "Τίποτα δεν πωλείται αυτή τη στιγμή",
|
||||
"Names go on sale when their owners list them from the dashboard. Have one to sell, or want a fresh one instead?": "Τα ονόματα βγαίνουν προς πώληση όταν οι ιδιοκτήτες τους τα καταχωρούν από τον πίνακα ελέγχου. Έχεις ένα να πουλήσεις ή προτιμάς ένα καινούργιο;",
|
||||
"Sell a name from your dashboard →": "Πούλησε ένα όνομα από τον πίνακα ελέγχου →",
|
||||
|
|
@ -604,5 +602,7 @@
|
|||
"Restyle selection": "Άλλαξε στυλ στην επιλογή",
|
||||
"Nothing selected": "Τίποτα επιλεγμένο",
|
||||
"Undo last change": "Αναίρεση τελευταίας αλλαγής",
|
||||
"Stop": "Στοπ"
|
||||
"Stop": "Στοπ",
|
||||
"unconfirmed · spendable now": "ανεπιβεβαίωτα · διαθέσιμα τώρα",
|
||||
"Price (BCH)": "Τιμή (BCH)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,7 +564,6 @@
|
|||
". A buyer completes it in one transaction — you are paid in the same transaction that moves the name, or not at all. No escrow, nothing to trust.": ". Un comprador la completa en una transacción — cobras en la misma transacción que mueve el nombre, o no cobras. Sin custodia, nada en lo que confiar.",
|
||||
"Checking the market…": "Consultando el mercado…",
|
||||
"Price (USD)": "Precio (USD)",
|
||||
"Price (sat)": "Precio (sat)",
|
||||
"List for sale →": "Poner en venta →",
|
||||
"Cancel listing →": "Cancelar anuncio →",
|
||||
"Cancelling removes the offer from the market and moves your certificate once (a no-op update, a few cents), so the signed offer can never be completed later.": "Cancelar retira la oferta del mercado y mueve tu certificado una vez (una actualización vacía, unos céntimos), para que la oferta firmada nunca pueda completarse después.",
|
||||
|
|
@ -581,7 +580,6 @@
|
|||
"Request declined": "Solicitud rechazada",
|
||||
"Open dashboard →": "Abrir panel →",
|
||||
"incl.": "incl.",
|
||||
"sat unconfirmed · spendable now": "sat sin confirmar · disponibles ya",
|
||||
"Nothing is for sale right now": "Ahora mismo no hay nada en venta",
|
||||
"Names go on sale when their owners list them from the dashboard. Have one to sell, or want a fresh one instead?": "Los nombres salen a la venta cuando sus dueños los publican desde el panel. ¿Tienes uno para vender, o prefieres uno nuevo?",
|
||||
"Sell a name from your dashboard →": "Vender un nombre desde tu panel →",
|
||||
|
|
@ -604,5 +602,7 @@
|
|||
"Restyle selection": "Cambiar estilo de la selección",
|
||||
"Nothing selected": "Nada seleccionado",
|
||||
"Undo last change": "Deshacer el último cambio",
|
||||
"Stop": "Detener"
|
||||
"Stop": "Detener",
|
||||
"unconfirmed · spendable now": "sin confirmar · disponibles ya",
|
||||
"Price (BCH)": "Precio (BCH)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,7 +564,6 @@
|
|||
". A buyer completes it in one transaction — you are paid in the same transaction that moves the name, or not at all. No escrow, nothing to trust.": ". Un acheteur la complète en une transaction — vous êtes payé dans la même transaction qui transfère le nom, ou pas du tout. Pas de séquestre, rien à devoir croire.",
|
||||
"Checking the market…": "Vérification du marché…",
|
||||
"Price (USD)": "Prix (USD)",
|
||||
"Price (sat)": "Prix (sat)",
|
||||
"List for sale →": "Mettre en vente →",
|
||||
"Cancel listing →": "Annuler l'annonce →",
|
||||
"Cancelling removes the offer from the market and moves your certificate once (a no-op update, a few cents), so the signed offer can never be completed later.": "L'annulation retire l'offre du marché et déplace votre certificat une fois (une mise à jour vide, quelques centimes), afin que l'offre signée ne puisse jamais être complétée plus tard.",
|
||||
|
|
@ -581,7 +580,6 @@
|
|||
"Request declined": "Demande refusée",
|
||||
"Open dashboard →": "Ouvrir le tableau de bord →",
|
||||
"incl.": "dont",
|
||||
"sat unconfirmed · spendable now": "sat non confirmés · disponibles maintenant",
|
||||
"Nothing is for sale right now": "Rien n'est à vendre pour l'instant",
|
||||
"Names go on sale when their owners list them from the dashboard. Have one to sell, or want a fresh one instead?": "Les noms sont mis en vente lorsque leurs propriétaires les listent depuis le tableau de bord. Vous en avez un à vendre, ou vous en voulez un tout neuf ?",
|
||||
"Sell a name from your dashboard →": "Vendre un nom depuis le tableau de bord →",
|
||||
|
|
@ -604,5 +602,7 @@
|
|||
"Restyle selection": "Restyler la sélection",
|
||||
"Nothing selected": "Rien de sélectionné",
|
||||
"Undo last change": "Annuler la dernière modification",
|
||||
"Stop": "Arrêter"
|
||||
"Stop": "Arrêter",
|
||||
"unconfirmed · spendable now": "non confirmés · disponibles maintenant",
|
||||
"Price (BCH)": "Prix (BCH)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,7 +564,6 @@
|
|||
". A buyer completes it in one transaction — you are paid in the same transaction that moves the name, or not at all. No escrow, nothing to trust.": ". Um comprador completa-a numa transação — recebe na mesma transação que move o nome, ou não recebe de todo. Sem custódia, nada em que confiar.",
|
||||
"Checking the market…": "A verificar o mercado…",
|
||||
"Price (USD)": "Preço (USD)",
|
||||
"Price (sat)": "Preço (sat)",
|
||||
"List for sale →": "Pôr à venda →",
|
||||
"Cancel listing →": "Cancelar anúncio →",
|
||||
"Cancelling removes the offer from the market and moves your certificate once (a no-op update, a few cents), so the signed offer can never be completed later.": "Cancelar retira a oferta do mercado e move o seu certificado uma vez (uma atualização vazia, alguns cêntimos), para que a oferta assinada nunca possa ser concluída mais tarde.",
|
||||
|
|
@ -581,7 +580,6 @@
|
|||
"Request declined": "Pedido recusado",
|
||||
"Open dashboard →": "Abrir painel →",
|
||||
"incl.": "incl.",
|
||||
"sat unconfirmed · spendable now": "sat por confirmar · disponíveis já",
|
||||
"Nothing is for sale right now": "De momento não há nada à venda",
|
||||
"Names go on sale when their owners list them from the dashboard. Have one to sell, or want a fresh one instead?": "Os nomes são postos à venda quando os donos os anunciam a partir do painel. Tem um para vender, ou prefere um novo?",
|
||||
"Sell a name from your dashboard →": "Vender um nome a partir do painel →",
|
||||
|
|
@ -604,5 +602,7 @@
|
|||
"Restyle selection": "Restilizar a seleção",
|
||||
"Nothing selected": "Nada selecionado",
|
||||
"Undo last change": "Anular a última alteração",
|
||||
"Stop": "Parar"
|
||||
"Stop": "Parar",
|
||||
"unconfirmed · spendable now": "por confirmar · disponíveis já",
|
||||
"Price (BCH)": "Preço (BCH)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -564,7 +564,6 @@
|
|||
". A buyer completes it in one transaction — you are paid in the same transaction that moves the name, or not at all. No escrow, nothing to trust.": ". Покупатель завершает её одной транзакцией — вы получаете оплату в той же транзакции, которая передаёт имя, либо не получаете вовсе. Без эскроу, доверять никому не нужно.",
|
||||
"Checking the market…": "Проверяем маркет…",
|
||||
"Price (USD)": "Цена (USD)",
|
||||
"Price (sat)": "Цена (сат)",
|
||||
"List for sale →": "Выставить на продажу →",
|
||||
"Cancel listing →": "Снять с продажи →",
|
||||
"Cancelling removes the offer from the market and moves your certificate once (a no-op update, a few cents), so the signed offer can never be completed later.": "Отмена убирает оферту с маркета и один раз перемещает ваш сертификат (пустое обновление, несколько центов), чтобы подписанную оферту нельзя было исполнить позже.",
|
||||
|
|
@ -581,7 +580,6 @@
|
|||
"Request declined": "Запрос отклонён",
|
||||
"Open dashboard →": "Открыть панель →",
|
||||
"incl.": "вкл.",
|
||||
"sat unconfirmed · spendable now": "сат не подтверждено · доступно сейчас",
|
||||
"Nothing is for sale right now": "Сейчас ничего не продаётся",
|
||||
"Names go on sale when their owners list them from the dashboard. Have one to sell, or want a fresh one instead?": "Имена появляются в продаже, когда владельцы выставляют их из панели. Есть что продать — или лучше зарегистрировать новое?",
|
||||
"Sell a name from your dashboard →": "Продать имя из панели →",
|
||||
|
|
@ -604,5 +602,7 @@
|
|||
"Restyle selection": "Изменить стиль выбранного",
|
||||
"Nothing selected": "Ничего не выбрано",
|
||||
"Undo last change": "Отменить последнее изменение",
|
||||
"Stop": "Стоп"
|
||||
"Stop": "Стоп",
|
||||
"unconfirmed · spendable now": "не подтверждено · доступно сейчас",
|
||||
"Price (BCH)": "Цена (BCH)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -495,13 +495,13 @@ process.exit(0);"</pre>
|
|||
<script type="importmap">
|
||||
{ "imports": { "@bitauth/libauth": "https://silentmode.st/js/libauth.js" } }
|
||||
</script>
|
||||
<script type="module" src="./js/register-flow.js?v=20260917bal"></script>
|
||||
<script type="module" src="./js/register-flow.js?v=20260920bits"></script>
|
||||
|
||||
<script src="./js/pricing.js?v=20260917market"></script>
|
||||
<script src="./js/pricing.js?v=20260920bits"></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=20260920compact"></script>
|
||||
<script defer src="./js/site-footer.js?v=20260917market"></script>
|
||||
<script defer src="./js/profile-menu.js?v=20260920m"></script>
|
||||
<script defer src="./js/profile-menu.js?v=20260920bits"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -174,6 +174,8 @@ document.querySelectorAll("[data-copy]").forEach((b) => b.addEventListener("clic
|
|||
// here, same as the register flow. Polled while the tab is visible and
|
||||
// refreshed right after anything this page broadcasts.
|
||||
const setText = (id, v) => { const el = $(id); if (el) el.textContent = v; };
|
||||
const fmtBits = (sats) => (window.siriusPricing?.formatBits || ((s) => (Number(s) / 100).toLocaleString("en-US") + " bits"))(sats);
|
||||
const fmtBch = (sats) => (window.siriusPricing?.formatBch || ((s) => (Number(s) / 1e8).toFixed(8).replace(/0+$/, "").replace(/\.$/, "") + " BCH"))(sats);
|
||||
let balEl = null, balTimer = null, balBusy = false;
|
||||
async function refreshBalance() {
|
||||
if (!wallet || balBusy) return;
|
||||
|
|
@ -183,10 +185,10 @@ async function refreshBalance() {
|
|||
if (!balEl) balEl = await BNS.connect();
|
||||
const b = await BNS.getBalance(balEl, wallet.watchedAddresses);
|
||||
const pending = b.sats - b.confirmedSats;
|
||||
setText("side-balance", fmtInt(b.sats));
|
||||
setText("w-sats", `${fmtInt(b.sats)} sat${pending > 0n ? ` (${fmtInt(pending)} unconfirmed, spendable now)` : ""}`);
|
||||
setText("side-balance", fmtBits(b.sats));
|
||||
setText("w-sats", `${fmtBits(b.sats)} · ${fmtBch(b.sats)}${pending > 0n ? ` (${fmtBits(pending)} unconfirmed, spendable now)` : ""}`);
|
||||
setText("w-utxos", String(b.coins));
|
||||
const pend = $("side-pending"); if (pend) { pend.hidden = pending <= 0n; setText("side-pending-sats", fmtInt(pending)); }
|
||||
const pend = $("side-pending"); if (pend) { pend.hidden = pending <= 0n; setText("side-pending-sats", fmtBits(pending)); }
|
||||
H.wallet = { ...(H.wallet || {}), sats: b.sats.toString(), utxo_count: b.coins };
|
||||
try { localStorage.setItem("siriusWalletInfo", JSON.stringify({ sats: b.sats.toString(), utxos: b.coins, names: H.names.length, tlds: H.tlds.length, at: Date.now() })); } catch {}
|
||||
window.dispatchEvent(new CustomEvent("sirius:balance", { detail: { sats: b.sats.toString(), pending: pending.toString() } }));
|
||||
|
|
@ -220,8 +222,7 @@ async function loadHoldings() {
|
|||
const setText = (id, v) => { const el = $(id); if (el) el.textContent = v; };
|
||||
setText("cnt-names", H.names.length); setText("cnt-tlds", H.tlds.length);
|
||||
if (H.wallet?.sats != null && $("side-balance").textContent === "—") {
|
||||
const s = fmtInt(H.wallet.sats);
|
||||
setText("side-balance", s); setText("w-sats", `${s} sat`); setText("w-utxos", String(H.wallet.utxo_count));
|
||||
setText("side-balance", fmtBits(H.wallet.sats)); setText("w-sats", `${fmtBits(H.wallet.sats)} · ${fmtBch(H.wallet.sats)}`); setText("w-utxos", String(H.wallet.utxo_count));
|
||||
}
|
||||
try { const prev = JSON.parse(localStorage.getItem("siriusWalletInfo") || "{}"); localStorage.setItem("siriusWalletInfo", JSON.stringify({ ...prev, sats: prev.sats ?? String(H.wallet?.sats ?? ""), names: H.names.length, tlds: H.tlds.length, at: Date.now() })); } catch {}
|
||||
if (H.chain?.height != null) setText("stat-height", fmtInt(H.chain.height));
|
||||
|
|
@ -661,12 +662,12 @@ const RATE = () => window.siriusPricing?.CHIPNET_SATS_PER_USD || 250000;
|
|||
let activeListing = null;
|
||||
function paintSell() {
|
||||
const st = $("sell-status");
|
||||
$("sell-rate").textContent = `rate ${fmtInt(RATE())} sat/USD (chipnet)`;
|
||||
$("sell-rate").textContent = `1 BCH ≈ ${fmtUsd(Math.round(1e8 / RATE() * 100) / 100)}${window.siriusPricing?.priceInfo ? " · " + window.siriusPricing.priceInfo() : ""}`;
|
||||
if (activeListing) {
|
||||
st.className = "status ok"; st.textContent = "This name is listed on the market.";
|
||||
$("sell-form").classList.add("hidden"); $("sell-active").classList.remove("hidden");
|
||||
const p = BigInt(activeListing.price_sats);
|
||||
$("sell-kv").innerHTML = [["Price", `${fmtInt(p)} sat (≈ ${esc(fmtUsd(Math.round(Number(p) / RATE() * 100) / 100))})`], ["Listed", esc(new Date(activeListing.created_at).toLocaleString())], ["Offer", `<code>${esc(activeListing.partial_tx.slice(0, 40))}…</code>`], ["Market page", `<a href="./market/" target="_blank" rel="noopener">open →</a>`]]
|
||||
$("sell-kv").innerHTML = [["Price", `${esc(fmtBch(p))} (≈ ${esc(fmtUsd(Math.round(Number(p) / RATE() * 100) / 100))})`], ["Listed", esc(new Date(activeListing.created_at).toLocaleString())], ["Offer", `<code>${esc(activeListing.partial_tx.slice(0, 40))}…</code>`], ["Market page", `<a href="./market/" target="_blank" rel="noopener">open →</a>`]]
|
||||
.map(([k, v]) => `<div class="k">${k}</div><div class="v">${v}</div>`).join("");
|
||||
} else {
|
||||
st.className = "status"; st.textContent = "Not for sale. Set a price to list it.";
|
||||
|
|
@ -678,13 +679,14 @@ async function loadListing(name) {
|
|||
try { const r = await fetch(`${API}/api/market/${encodeURIComponent(name)}`, { cache: "no-store" }); if (r.ok) activeListing = await r.json(); } catch {}
|
||||
if (current.name === name) paintSell();
|
||||
}
|
||||
$("sell-usd").addEventListener("input", () => { const v = Number(String($("sell-usd").value).replace(/[^\d.]/g, "")); $("sell-sats").value = v > 0 ? String(Math.round(v * RATE())) : ""; });
|
||||
$("sell-sats").addEventListener("input", () => { const s = Number(String($("sell-sats").value).replace(/\D/g, "")); $("sell-usd").value = s > 0 ? String(Math.round(s / RATE() * 100) / 100) : ""; });
|
||||
const bchStr = (sats) => (Number(sats) / 1e8).toFixed(8).replace(/0+$/, "").replace(/\.$/, "");
|
||||
$("sell-usd").addEventListener("input", () => { const v = Number(String($("sell-usd").value).replace(/[^\d.]/g, "")); $("sell-bch").value = v > 0 ? bchStr(Math.round(v * RATE())) : ""; });
|
||||
$("sell-bch").addEventListener("input", () => { const b = Number(String($("sell-bch").value).replace(/[^\d.]/g, "")); $("sell-usd").value = b > 0 ? String(Math.round(b * 1e8 / RATE() * 100) / 100) : ""; });
|
||||
$("sell-list").addEventListener("click", async () => {
|
||||
if (!current.entry || !wallet) return;
|
||||
if (wallet.source === "wc") return setMsg("sell-msg", "Listing from an external wallet lands in the next drop — sign in with the built-in wallet.", "err");
|
||||
const sats = BigInt(Number(String($("sell-sats").value).replace(/\D/g, "")) || 0);
|
||||
if (sats < 10000n) return setMsg("sell-msg", "Set a price of at least 10,000 sat.", "err");
|
||||
const sats = BigInt(Math.round((Number(String($("sell-bch").value).replace(/[^\d.]/g, "")) || 0) * 1e8));
|
||||
if (sats < 10000n) return setMsg("sell-msg", "Set a price of at least 0.0001 BCH.", "err");
|
||||
const push = logger("sell-log"); const btn = $("sell-list"); btn.disabled = true; btn.textContent = "Signing…"; setMsg("sell-msg", "");
|
||||
let el = null;
|
||||
try {
|
||||
|
|
@ -701,7 +703,7 @@ $("sell-list").addEventListener("click", async () => {
|
|||
if (!r.ok) throw new Error(j.error || `API ${r.status}`);
|
||||
push("listed on the market");
|
||||
activeListing = j.listing; paintSell();
|
||||
setMsg("sell-msg", `Listed for ${fmtInt(sats)} sat. Nothing moves until a buyer pays that price.`, "ok");
|
||||
setMsg("sell-msg", `Listed for ${fmtBch(sats)}. Nothing moves until a buyer pays that price.`, "ok");
|
||||
} catch (e) { setMsg("sell-msg", "Failed: " + (e.message || e), "err"); push("error: " + (e.message || e)); }
|
||||
finally { btn.disabled = false; btn.textContent = "List for sale →"; try { el?.close?.(); } catch {} }
|
||||
});
|
||||
|
|
@ -948,12 +950,11 @@ $("tld-ed-save").addEventListener("click", async () => {
|
|||
});
|
||||
|
||||
// ---------- new TLD ----------
|
||||
const CHIPNET_SATS_PER_USD = 250_000;
|
||||
function usdToSats(usd) { const n = Number(String(usd).replace(/[^\d.]/g, "")) || 0; return Math.max(0, Math.round(n * CHIPNET_SATS_PER_USD)); }
|
||||
function usdToSats(usd) { const n = Number(String(usd).replace(/[^\d.]/g, "")) || 0; return Math.max(0, Math.round(n * RATE())); }
|
||||
function updateTldPrice() {
|
||||
const sats = usdToSats($("tld-usd").value.trim() || "0");
|
||||
$("tld-price").innerHTML = `= <b>${sats.toLocaleString()}</b> sats · rate <b>${CHIPNET_SATS_PER_USD.toLocaleString()}</b> sats/USD (chipnet)`;
|
||||
$("tld-submit").textContent = `Register (~${sats.toLocaleString()} sats)`;
|
||||
$("tld-price").innerHTML = `= <b>${esc(fmtBits(sats))}</b> · 1 BCH ≈ <b>${esc(fmtUsd(Math.round(1e8 / RATE() * 100) / 100))}</b>${window.siriusPricing?.priceInfo ? " · " + esc(window.siriusPricing.priceInfo()) : ""}`;
|
||||
$("tld-submit").textContent = `Register (~${fmtBits(sats)})`;
|
||||
}
|
||||
const validateTldLabel = (l) => /^[a-z0-9-]{1,16}$/.test(l);
|
||||
function updateTldButtons() { const ok = validateTldLabel($("tld-label").value.trim().toLowerCase()); $("tld-check").disabled = !ok || !wallet; $("tld-submit").disabled = !ok || !wallet; }
|
||||
|
|
@ -1027,3 +1028,6 @@ $("pin-save").addEventListener("click", async () => {
|
|||
catch (e) { setMsg("pin-msg", e.message || String(e), "err"); }
|
||||
});
|
||||
$("set-clearpin").addEventListener("click", () => { window.siriusPin?.clear?.(); paintSettings(); setMsg("set-msg", "PIN removed.", "ok"); });
|
||||
|
||||
// Live BCH/USD rate (pricing.js) — repaint everything priced in USD.
|
||||
window.addEventListener("sirius:price", () => { try { updateTldPrice(); } catch {} try { if (current.name) paintSell(); } catch {} });
|
||||
|
|
|
|||
13
js/market.js
13
js/market.js
|
|
@ -13,6 +13,8 @@ const API = "https://silentmode.st";
|
|||
const $ = (id) => document.getElementById(id);
|
||||
const esc = (s) => String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
|
||||
const fmtInt = (n) => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
const bch = (sats) => (window.siriusPricing?.formatBch || ((s) => (Number(s) / 1e8).toFixed(8).replace(/0+$/, "").replace(/\.$/, "") + " BCH"))(sats);
|
||||
const bits = (sats) => (window.siriusPricing?.formatBits || ((s) => (Number(s) / 100).toLocaleString("en-US") + " bits"))(sats);
|
||||
const usd = (sats) => { const r = window.siriusPricing?.CHIPNET_SATS_PER_USD || 250000; const v = Number(sats) / r; return (window.siriusPricing?.formatUsd || ((n) => "$" + n.toFixed(2)))(Math.round(v * 100) / 100); };
|
||||
const shortAddr = (a) => (a ? a.replace(/^[^:]+:/, "").slice(0, 8) + "…" + a.slice(-5) : "—");
|
||||
|
||||
|
|
@ -66,11 +68,11 @@ function render() {
|
|||
return;
|
||||
}
|
||||
status.hidden = false;
|
||||
status.className = "status"; status.textContent = `${listings.length} name${listings.length === 1 ? "" : "s"} for sale. Prices are set by the sellers; you pay the price plus about 1,300 sat of chain dust and fee.`;
|
||||
status.className = "status"; status.textContent = `${listings.length} name${listings.length === 1 ? "" : "s"} for sale. Prices are set by the sellers; you pay the price plus about 13 bits of chain dust and fee.`;
|
||||
$("list").innerHTML = rows.length ? rows.map((l) => `
|
||||
<div class="row">
|
||||
<div class="n">${esc(l.label)}.<span class="tld">${esc(l.tld)}</span> ${wallet && l.seller === wallet.address ? '<span class="badge">yours</span>' : ""}</div>
|
||||
<div class="price"><b>${fmtInt(l.price_sats)} sat</b><span>≈ ${esc(usd(l.price_sats))}</span></div>
|
||||
<div class="price"><b>${esc(bch(l.price_sats))}</b><span>≈ ${esc(usd(l.price_sats))}</span></div>
|
||||
<div><button class="btn acid small" data-buy="${esc(l.name)}" ${wallet && l.seller === wallet.address ? "disabled" : ""}>Buy →</button></div>
|
||||
<div class="meta"><span>seller ${esc(shortAddr(l.seller))}</span><span>·</span><span>listed ${esc(new Date(l.created_at).toLocaleDateString())}</span><span>·</span><a href="${API}/bns/${encodeURIComponent(l.name)}/" target="_blank" rel="noopener">view site →</a></div>
|
||||
</div>`).join("") : `<div class="empty">Nothing matches that filter.</div>`;
|
||||
|
|
@ -87,11 +89,11 @@ function openBuy(name) {
|
|||
const price = BigInt(selected.price_sats);
|
||||
const check = BNS.verifyListing(selected, { category: selected.category });
|
||||
$("buy-kv").innerHTML = [
|
||||
["Price", `${fmtInt(price)} sat (≈ ${esc(usd(price))})`],
|
||||
["Price", `${esc(bch(price))} (≈ ${esc(usd(price))})`],
|
||||
["Seller", esc(selected.seller)],
|
||||
["You receive", "the name's certificate, to your token address"],
|
||||
["Offer check", check.ok ? "seller signature valid" : "INVALID: " + esc(check.error)],
|
||||
["Extra", "≈ 1,600 sat dust + fee"],
|
||||
["Extra", "≈ 16 bits dust + fee"],
|
||||
].map(([k, v]) => `<div class="k">${k}</div><div class="v">${v}</div>`).join("");
|
||||
$("buy-steps").className = "steps"; $("buy-steps").innerHTML = ""; setMsg("");
|
||||
const canBuy = !!wallet && check.ok && wallet.address !== selected.seller;
|
||||
|
|
@ -112,7 +114,7 @@ $("buy-go").addEventListener("click", async () => {
|
|||
const utxos = await BNS.getUtxosForAddresses(el, wallet.watchedAddresses);
|
||||
push(`wallet has ${utxos.filter((u) => !u.token).length} spendable coin(s)`);
|
||||
const built = BNS.completeSale({ listing: selected, buyerAddress: wallet.address, buyerTokenAddress: wallet.tokenAddress, utxos, records: selected.records || {}, addressToLockingBytecode: BNS.addressToLockingBytecode });
|
||||
push(`built sale · price ${fmtInt(built.costs.priceSats)} sat · fee ${built.costs.chainFeeSats} sat`);
|
||||
push(`built sale · price ${bch(built.costs.priceSats)} · fee ${bits(built.costs.chainFeeSats)}`);
|
||||
const signed = BNS.signInputs(built.transaction, built.sourceOutputs, (h) => wallet.keyFor(h), { skip: [built.sellerInputIndex] });
|
||||
push("signed your inputs (the seller's signature is already in place)");
|
||||
const txid = await BNS.broadcast(el, signed.hex);
|
||||
|
|
@ -131,3 +133,4 @@ $("buy-go").addEventListener("click", async () => {
|
|||
wallet = await restoreWallet();
|
||||
await load();
|
||||
})();
|
||||
window.addEventListener("sirius:price", () => { if (listings.length) render(); });
|
||||
|
|
|
|||
|
|
@ -16,9 +16,52 @@
|
|||
// Chipnet placeholder rate: mainnet swaps this for a real BCH/USD oracle.
|
||||
// The numbers keep the demo transactions in the "few chipnet coins" range
|
||||
// so a single faucet visit covers a name or a TLD.
|
||||
const CHIPNET_SATS_PER_USD = 250_000;
|
||||
|
||||
const usdToSats = (usd) => BigInt(Math.max(0, Math.round(Number(usd) * CHIPNET_SATS_PER_USD)));
|
||||
// BCH/USD rate. Live: the gateway's /api/price (median of several exchanges)
|
||||
// or, if that is unreachable, the same public tickers straight from the
|
||||
// browser; the last good rate is remembered per browser; the constant is
|
||||
// only the very first paint before anything answers. Chipnet coins have no
|
||||
// market, so the mainnet rate is what makes "$7 per name" mean something.
|
||||
const FALLBACK_SATS_PER_USD = 400_000;
|
||||
let SATS_PER_USD = FALLBACK_SATS_PER_USD;
|
||||
let priceMeta = { usd: null, at: 0, sources: 0, origin: "fallback" };
|
||||
try { const c = JSON.parse(localStorage.getItem("siriusPrice") || "null"); if (c && c.usd > 0) { SATS_PER_USD = Math.round(1e8 / c.usd); priceMeta = { ...c, origin: "cached" }; } } catch {}
|
||||
const usdToSats = (usd) => BigInt(Math.max(0, Math.round(Number(usd) * SATS_PER_USD)));
|
||||
const PRICE_API = "https://silentmode.st/api/price";
|
||||
const BROWSER_SOURCES = [
|
||||
["coinbase", "https://api.coinbase.com/v2/prices/BCH-USD/spot", (j) => Number(j?.data?.amount)],
|
||||
["kraken", "https://api.kraken.com/0/public/Ticker?pair=BCHUSD", (j) => Number(Object.values(j?.result || {})[0]?.c?.[0])],
|
||||
["binance", "https://api.binance.com/api/v3/ticker/price?symbol=BCHUSDT", (j) => Number(j?.price)],
|
||||
["coingecko", "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin-cash&vs_currencies=usd", (j) => Number(j?.["bitcoin-cash"]?.usd)],
|
||||
];
|
||||
function applyPrice(usd, sources, origin) {
|
||||
if (!(usd > 0)) return false;
|
||||
SATS_PER_USD = Math.round(1e8 / usd);
|
||||
priceMeta = { usd, at: Date.now(), sources, origin };
|
||||
try { localStorage.setItem("siriusPrice", JSON.stringify(priceMeta)); } catch {}
|
||||
try { window.dispatchEvent(new CustomEvent("sirius:price", { detail: priceMeta })); } catch {}
|
||||
return true;
|
||||
}
|
||||
let priceLoad = null;
|
||||
function loadPrice({ force = false } = {}) {
|
||||
if (priceLoad && !force) return priceLoad;
|
||||
priceLoad = (async () => {
|
||||
try {
|
||||
const r = await fetch(PRICE_API, { cache: "no-store", signal: AbortSignal.timeout(6000) });
|
||||
const j = await r.json();
|
||||
if (j && j.usd > 0 && !j.stale) return applyPrice(j.usd, j.median_of || 0, "gateway");
|
||||
} catch {}
|
||||
const got = (await Promise.allSettled(BROWSER_SOURCES.map(async ([name, url, pick]) => {
|
||||
const r = await fetch(url, { signal: AbortSignal.timeout(6000) }); if (!r.ok) throw new Error(String(r.status));
|
||||
const v = pick(await r.json()); if (!(v > 0)) throw new Error("no price"); return v;
|
||||
}))).filter((x) => x.status === "fulfilled").map((x) => x.value).sort((a, b) => a - b);
|
||||
if (got.length) { const m = Math.floor(got.length / 2); return applyPrice(got.length % 2 ? got[m] : (got[m - 1] + got[m]) / 2, got.length, "exchanges"); }
|
||||
return false;
|
||||
})();
|
||||
return priceLoad;
|
||||
}
|
||||
const priceInfo = () => priceMeta.usd ? `${priceMeta.origin === "gateway" || priceMeta.origin === "exchanges" ? `median of ${priceMeta.sources} exchange${priceMeta.sources === 1 ? "" : "s"}` : priceMeta.origin === "cached" ? "last known rate" : "fallback rate"}${priceMeta.at ? ", " + Math.max(0, Math.round((Date.now() - priceMeta.at) / 60000)) + " min ago" : ""}` : "fallback rate";
|
||||
loadPrice();
|
||||
setInterval(() => loadPrice({ force: true }), 5 * 60 * 1000);
|
||||
|
||||
const cleanLabel = (s) => String(s || "").toLowerCase().replace(/[^a-z0-9-]/g, "");
|
||||
|
||||
|
|
@ -201,9 +244,22 @@
|
|||
if (n >= 1 && n === Math.floor(n)) return `$${n}`;
|
||||
return `$${n.toFixed(2)}`;
|
||||
}
|
||||
function formatSats(sats) {
|
||||
return `${BigInt(sats || 0n).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")} sat`;
|
||||
// Money is shown in BCH (prices) and bits (fees, balances); 1 bit = 100
|
||||
// satoshi, 1 BCH = 1,000,000 bits. Satoshi never appears in the UI.
|
||||
const group = (s) => String(s).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
function formatBch(sats) {
|
||||
const n = BigInt(sats || 0n); const neg = n < 0n; const a = neg ? -n : n;
|
||||
const whole = a / 100000000n, frac = (a % 100000000n).toString().padStart(8, "0").replace(/0+$/, "");
|
||||
return `${neg ? "-" : ""}${group(whole)}${frac ? "." + frac : ""} BCH`;
|
||||
}
|
||||
function formatBits(sats) {
|
||||
const n = BigInt(sats || 0n); const neg = n < 0n; const a = neg ? -n : n;
|
||||
const whole = a / 100n, frac = (a % 100n).toString().padStart(2, "0").replace(/0+$/, "");
|
||||
return `${neg ? "-" : ""}${group(whole)}${frac ? "." + frac : ""} bits`;
|
||||
}
|
||||
const formatSats = formatBits; // legacy name, same unit policy
|
||||
const bchToSats = (bch) => BigInt(Math.max(0, Math.round(Number(String(bch).replace(/[^\d.]/g, "")) * 1e8)));
|
||||
const satsToBch = (sats) => Number(BigInt(sats || 0n)) / 1e8;
|
||||
function round2(n) { return Math.round(Number(n) * 100) / 100; }
|
||||
|
||||
window.siriusPricing = {
|
||||
|
|
@ -211,8 +267,18 @@
|
|||
priceForTld,
|
||||
formatUsd,
|
||||
formatSats,
|
||||
formatBch,
|
||||
formatBits,
|
||||
bchToSats,
|
||||
satsToBch,
|
||||
usdToSats,
|
||||
CHIPNET_SATS_PER_USD,
|
||||
// live rate (getters: callers that read the old constant see the current value)
|
||||
get CHIPNET_SATS_PER_USD() { return SATS_PER_USD; },
|
||||
get SATS_PER_USD() { return SATS_PER_USD; },
|
||||
get bchUsd() { return priceMeta.usd || 1e8 / SATS_PER_USD; },
|
||||
priceInfo,
|
||||
loadPrice,
|
||||
priceReady: () => priceLoad || loadPrice(),
|
||||
// TLD owner policy layer
|
||||
loadTldPolicies,
|
||||
setTldPolicies,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
// Wallet-only menu: identity, balance, receive, settings, sign out.
|
||||
// Names/TLDs/admin live behind the Dashboard button next to this one.
|
||||
const info = readWalletInfo();
|
||||
const bal = info?.sats != null ? `${fmtInt(info.sats)} sat` : "—";
|
||||
const bal = info?.sats != null ? (window.siriusPricing?.formatBits ? window.siriusPricing.formatBits(info.sats) : `${(Number(info.sats) / 100).toLocaleString("en-US")} bits`) : "—";
|
||||
const held = info ? `${info.names ?? 0} name${info.names === 1 ? "" : "s"} · ${info.tlds ?? 0} TLD${info.tlds === 1 ? "" : "s"}` : "open the dashboard to load";
|
||||
menu.innerHTML = `
|
||||
<div class="profile-header">
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import * as BNS from "https://silentmode.st/js/bns-register.js?v=20260917market"
|
|||
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const esc = (s) => String(s).replace(/[&<>"']/g, (c) => ({ "&":"&","<":"<",">":">",'"':""","'":"'" }[c]));
|
||||
// Amounts are shown in bits (1 bit = 100 satoshi); satoshi never reach the UI.
|
||||
const bits = (v) => (window.siriusPricing?.formatBits || ((s) => (Number(s) / 100).toLocaleString("en-US") + " bits"))(v);
|
||||
const sats = (v) => Number(v).toLocaleString("en-US");
|
||||
|
||||
// ---------- inject CSS + modal HTML ----------
|
||||
|
|
@ -632,7 +634,7 @@ async function stepExternalConfirm(session, label) {
|
|||
const quote = await BNS.quoteRegistration(c, { name: state.name, ownerAddress: owner, records: {}, ...feeOverride });
|
||||
const rows = BNS.priceSummary(quote.costs).map((l) => `
|
||||
<tr class="${l.total ? "total" : ""}"><td>${esc(l.label)}${l.note ? `<small>${esc(l.note)}</small>` : ""}</td>
|
||||
<td>${sats(l.sats)} sat</td></tr>`).join("");
|
||||
<td>${bits(l.sats)}</td></tr>`).join("");
|
||||
|
||||
render(`
|
||||
<h3>Confirm ${esc(quote.displayName)}</h3>
|
||||
|
|
@ -900,7 +902,7 @@ async function stepFund() {
|
|||
try { const prev = JSON.parse(localStorage.getItem("siriusWalletInfo") || "{}"); localStorage.setItem("siriusWalletInfo", JSON.stringify({ ...prev, sats: b.sats.toString(), utxos: b.coins, at: Date.now() })); } catch {}
|
||||
const enough = b.sats >= 20000n;
|
||||
$("bal").innerHTML = b.sats > 0n
|
||||
? `<b class="ok">${sats(b.sats)} sat</b> available (${b.coins} coin${b.coins===1?"":"s"})`
|
||||
? `<b class="ok">${bits(b.sats)}</b> available (${b.coins} coin${b.coins===1?"":"s"})`
|
||||
+ (enough ? "" : ` — a little more is needed to cover the registration.`)
|
||||
: `Waiting for coins… this page is watching the chain live.`;
|
||||
$("next").disabled = !enough;
|
||||
|
|
@ -933,7 +935,7 @@ async function stepConfirm() {
|
|||
|
||||
const rows = BNS.priceSummary(quote.costs).map((l) => `
|
||||
<tr class="${l.total ? "total" : ""}"><td>${esc(l.label)}${l.note ? `<small>${esc(l.note)}</small>` : ""}</td>
|
||||
<td>${sats(l.sats)} sat</td></tr>`).join("");
|
||||
<td>${bits(l.sats)}</td></tr>`).join("");
|
||||
|
||||
render(`
|
||||
<h3>Confirm ${esc(quote.displayName)}</h3>
|
||||
|
|
@ -967,9 +969,9 @@ async function stepConfirmTld() {
|
|||
the registry operator for every second-level name under it.</p>
|
||||
<table class="price">
|
||||
<tr><td>Service fee${feeSats === 0n ? " <small>(none on chipnet)</small>" : ""}</td>
|
||||
<td>${sats(feeSats)} sat</td></tr>
|
||||
<td>${bits(feeSats)}</td></tr>
|
||||
<tr><td>Beacon dust + chain fee <small>(covered by wallet)</small></td>
|
||||
<td>~1,300 sat</td></tr>
|
||||
<td>~13 bits</td></tr>
|
||||
</table>
|
||||
<div class="note" style="margin-top:16px">Minted to <span class="mono">${esc(owner)}</span>.
|
||||
That wallet becomes the operator for this TLD.</div>
|
||||
|
|
@ -990,7 +992,7 @@ async function stepConfirmTld() {
|
|||
// opts: { feeSats, kind: "name"|"tld", back, next }
|
||||
function stepApprove(opts) {
|
||||
const { feeSats, kind, back, next } = opts;
|
||||
const feeLine = feeSats && feeSats > 0n ? `<b class="ok">${sats(feeSats)} sat</b>` : `<b class="ok">Service fee waived on chipnet</b>`;
|
||||
const feeLine = feeSats && feeSats > 0n ? `<b class="ok">${bits(feeSats)}</b>` : `<b class="ok">Service fee waived on chipnet</b>`;
|
||||
const target = kind === "tld" ? `.<b>${esc(state.name)}</b>` : `<b>${esc(state.name)}</b>`;
|
||||
|
||||
// Signed in with a live wallet and no "ask for PIN before payments"
|
||||
|
|
|
|||
18
portal.html
18
portal.html
|
|
@ -298,8 +298,8 @@
|
|||
<div class="who">
|
||||
<div class="lbl">Signed in</div>
|
||||
<div class="addr" id="side-addr">—</div>
|
||||
<div class="net">chipnet · <span id="side-balance">—</span> sat <button class="refresh" id="side-refresh" title="Refresh balance" aria-label="Refresh balance">↻</button></div>
|
||||
<div class="net pending" id="side-pending" hidden>incl. <span id="side-pending-sats">0</span> sat unconfirmed · spendable now</div>
|
||||
<div class="net">chipnet · <span id="side-balance">—</span> <button class="refresh" id="side-refresh" title="Refresh balance" aria-label="Refresh balance">↻</button></div>
|
||||
<div class="net pending" id="side-pending" hidden>incl. <span id="side-pending-sats">0</span> unconfirmed · spendable now</div>
|
||||
</div>
|
||||
<button class="item" data-go="studio"><span class="ic">🎨</span>Web-Builder</button>
|
||||
<button class="item active" data-go="domains"><span class="ic">🌐</span>Domain names<span class="cnt" id="cnt-names">0</span></button>
|
||||
|
|
@ -364,7 +364,7 @@
|
|||
<div id="sell-form">
|
||||
<div class="row" style="align-items:flex-end">
|
||||
<div><label style="margin-top:0">Price (USD)</label><input type="text" id="sell-usd" placeholder="25" inputmode="decimal" style="max-width:160px"></div>
|
||||
<div><label style="margin-top:0">Price (sat)</label><input type="text" id="sell-sats" placeholder="6250000" inputmode="numeric" style="max-width:200px"></div>
|
||||
<div><label style="margin-top:0">Price (BCH)</label><input type="text" id="sell-bch" placeholder="0.0625" inputmode="decimal" style="max-width:200px"></div>
|
||||
<span class="dim" id="sell-rate"></span>
|
||||
</div>
|
||||
<div class="row end"><button class="btn acid" id="sell-list">List for sale →</button></div>
|
||||
|
|
@ -561,10 +561,10 @@
|
|||
<input type="text" id="tld-label" placeholder="myregistry" autocomplete="off" spellcheck="false" maxlength="16">
|
||||
<label style="margin-top:12px">Service fee (USD) <span class="dim" style="margin-left:6px">chipnet test rate</span></label>
|
||||
<input type="text" id="tld-usd" value="5">
|
||||
<div class="status" id="tld-price">= <b>0</b> sats · rate <b>0</b> sats/USD</div>
|
||||
<div class="status" id="tld-price">= <b>0 bits</b></div>
|
||||
<div class="row">
|
||||
<button class="btn ghost small" id="tld-check" disabled>Check availability</button>
|
||||
<button class="btn acid small" id="tld-submit" disabled>Register (~0 sats)</button>
|
||||
<button class="btn acid small" id="tld-submit" disabled>Register (~0 bits)</button>
|
||||
</div>
|
||||
<div id="tld-log" class="status" style="display:none;font-family:var(--mono);font-size:12.5px;margin-top:12px"></div>
|
||||
<div id="tld-msg" style="margin-top:10px;font-size:13.5px"></div>
|
||||
|
|
@ -677,11 +677,11 @@
|
|||
</script>
|
||||
<script src="./js/session.js?v=20260917dash"></script>
|
||||
<script src="./js/pin-escrow.js?v=20260909pin"></script>
|
||||
<script src="./js/pricing.js?v=20260917market"></script>
|
||||
<script type="module" src="./js/dashboard.js?v=20260917bal"></script>
|
||||
<script src="./js/pricing.js?v=20260920bits"></script>
|
||||
<script type="module" src="./js/dashboard.js?v=20260920bits"></script>
|
||||
<script defer src="./js/theme.js?v=20260920compact"></script>
|
||||
<script defer src="./js/site-footer.js?v=20260917market"></script>
|
||||
<script type="module" src="./js/register-flow.js?v=20260917bal"></script>
|
||||
<script defer src="./js/profile-menu.js?v=20260920m"></script>
|
||||
<script type="module" src="./js/register-flow.js?v=20260920bits"></script>
|
||||
<script defer src="./js/profile-menu.js?v=20260920bits"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
10
tld.html
10
tld.html
|
|
@ -171,7 +171,7 @@
|
|||
<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 CHIPNET_SATS_PER_USD = 400_000; // first-paint fallback only; pricing.js serves the live rate
|
||||
const DEFAULT_USD = 5;
|
||||
|
||||
const $ = (id) => document.getElementById(id);
|
||||
|
|
@ -273,7 +273,7 @@
|
|||
// 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 fee = p ? p.sats : BigInt(DEFAULT_USD * (window.siriusPricing?.SATS_PER_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.
|
||||
|
|
@ -303,12 +303,12 @@
|
|||
})();
|
||||
</script>
|
||||
|
||||
<script type="module" src="./js/register-flow.js?v=20260917bal"></script>
|
||||
<script src="./js/pricing.js?v=20260917market"></script>
|
||||
<script type="module" src="./js/register-flow.js?v=20260920bits"></script>
|
||||
<script src="./js/pricing.js?v=20260920bits"></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=20260920compact"></script>
|
||||
<script defer src="./js/site-footer.js?v=20260917market"></script>
|
||||
<script defer src="./js/profile-menu.js?v=20260920m"></script>
|
||||
<script defer src="./js/profile-menu.js?v=20260920bits"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue