feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
// Marketplace page: list the gateway's active offers and complete a purchase.
//
// A listing is the seller's partially signed transaction (see
// Argus/src/lib/market-tx.js). Buying = verify it locally, append our own
// funding inputs and the outputs that give us the certificate and update
// the registry, sign our inputs, broadcast. The seller's signature only
// stays valid while their certificate UTXO is unspent, so the gateway prunes
// stale offers and the buyer's broadcast is the final arbiter.
2026-09-20 19:20:30 +02:00
import * as BNS from "https://silentmode.st/js/bns-register.js?v=20260920usd" ;
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
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 , "," ) ;
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).
2026-09-20 18:18:43 +02:00
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 ) ;
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
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 ) ; } ;
2026-09-20 19:20:30 +02:00
const fmtUsdC = ( cents ) => ( window . siriusPricing ? . formatUsd || ( ( n ) => "$" + n . toFixed ( 2 ) ) ) ( Math . round ( Number ( cents ) ) / 100 ) ;
const satsForCents = ( cents ) => Math . round ( Number ( cents ) / 100 * ( window . siriusPricing ? . CHIPNET _SATS _PER _USD || 400000 ) ) ;
const clampSats = ( sats , l ) => Math . min ( Number ( l . ceil _sats ) , Math . max ( Number ( l . floor _sats ) , sats ) ) ;
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
const shortAddr = ( a ) => ( a ? a . replace ( /^[^:]+:/ , "" ) . slice ( 0 , 8 ) + "…" + a . slice ( - 5 ) : "—" ) ;
let listings = [ ] ;
let wallet = null ;
let selected = null ;
async function restoreWallet ( ) {
if ( window . siriusWallet ) return window . siriusWallet ;
const S = window . siriusSession ;
if ( ! S ? . restore ) return null ;
try {
const s = await S . restore ( ) ;
if ( ! s ? . mnemonic ) return null ;
const w = await BNS . BuiltInWallet . fromMnemonic ( s . mnemonic , BNS . CHIPNET _PREFIX , s . accountPath || undefined ) ;
window . siriusWallet = w ;
return w ;
} catch { return null ; }
}
async function load ( ) {
const status = $ ( "status" ) ;
try {
const r = await fetch ( ` ${ API } /api/market ` , { cache : "no-store" } ) ;
if ( ! r . ok ) throw new Error ( "API " + r . status ) ;
const j = await r . json ( ) ;
listings = ( j . listings || [ ] ) . map ( ( l ) => ( { ... l , label : l . name . split ( "." ) [ 0 ] , tld : l . tld || l . name . split ( "." ) . pop ( ) } ) ) ;
render ( ) ;
} catch ( e ) { status . className = "status err" ; status . textContent = "Could not load listings: " + ( e . message || e ) ; }
}
function render ( ) {
const q = ( $ ( "q" ) . value || "" ) . toLowerCase ( ) . trim ( ) ;
const sort = $ ( "sort" ) . value ;
const tldSel = $ ( "tld" ) ;
const tlds = [ ... new Set ( listings . map ( ( l ) => l . tld ) ) ] . sort ( ) ;
const keep = tldSel . value ;
tldSel . innerHTML = ` <option value="">All TLDs</option> ` + tlds . map ( ( t ) => ` <option value=" ${ esc ( t ) } " ${ t === keep ? " selected" : "" } >. ${ esc ( t ) } </option> ` ) . join ( "" ) ;
let rows = listings . filter ( ( l ) => ( ! q || l . name . includes ( q ) ) && ( ! tldSel . value || l . tld === tldSel . value ) ) ;
2026-09-20 19:20:30 +02:00
const priceOf = ( l ) => ( l . kind === "usd" ? clampSats ( satsForCents ( l . target _cents ) , l ) : Number ( l . price _sats ) ) ;
rows . sort ( ( a , b ) => sort === "name" ? a . name . localeCompare ( b . name ) : sort === "new" ? Date . parse ( b . created _at ) - Date . parse ( a . created _at ) : priceOf ( a ) - priceOf ( b ) ) ;
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
$ ( "count" ) . textContent = ` ${ rows . length } of ${ listings . length } ` ;
const status = $ ( "status" ) ;
2026-09-20 00:58:25 +02:00
document . querySelector ( ".toolbar" ) . hidden = ! listings . length ;
if ( ! listings . length ) {
status . hidden = true ;
$ ( "list" ) . innerHTML = ` <div class="empty big">
< div class = "ico" > 🛒 < / d i v >
< h3 > Nothing is for sale right now < / h 3 >
< p > Names go on sale when their owners list them from the dashboard . Have one to sell , or want a fresh one instead ? < / p >
< div class = "cta" > < a class = "btn acid" href = "./portal.html#domains" > Sell a name from your dashboard → < /a><a class="btn ghost" href="./ # search - input " > Register a new name < / a > < / d i v >
< / d i v > ` ;
return ;
}
status . hidden = false ;
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).
2026-09-20 18:18:43 +02:00
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. ` ;
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
$ ( "list" ) . innerHTML = rows . length ? rows . map ( ( l ) => `
< div class = "row" >
< div class = "n" > $ { esc ( l . label ) } . < span class = "tld" > $ { esc ( l . tld ) } < / s p a n > $ { w a l l e t & & l . s e l l e r = = = w a l l e t . a d d r e s s ? ' < s p a n c l a s s = " b a d g e " > y o u r s < / s p a n > ' : " " } < / d i v >
2026-09-20 19:20:30 +02:00
< div class = "price" > $ { l . kind === "usd"
? ` <b> ${ esc ( fmtUsdC ( l . target _cents ) ) } </b><span>fixed in USD · today ≈ ${ esc ( bch ( satsForCents ( l . target _cents ) ) ) } </span> `
: ` <b> ${ esc ( bch ( l . price _sats ) ) } </b><span>≈ ${ esc ( usd ( l . price _sats ) ) } </span> ` } < / d i v >
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
< div > < button class = "btn acid small" data - buy = "${esc(l.name)}" $ { wallet && l . seller === wallet . address ? "disabled" : "" } > Buy → < / b u t t o n > < / d i v >
< div class = "meta" > < span > seller $ { esc ( shortAddr ( l . seller ) ) } < / s p a n > < s p a n > · < / s p a n > < s p a n > l i s t e d $ { e s c ( n e w D a t e ( l . c r e a t e d _ a t ) . t o L o c a l e D a t e S t r i n g ( ) ) } < / s p a n > < s p a n > · < / s p a n > < a h r e f = " $ { A P I } / b n s / $ { e n c o d e U R I C o m p o n e n t ( l . n a m e ) } / " t a r g e t = " _ b l a n k " r e l = " n o o p e n e r " > v i e w s i t e → < / a > < / d i v >
< / d i v > ` ) . j o i n ( " " ) : ` < d i v c l a s s = " e m p t y " > N o t h i n g m a t c h e s t h a t f i l t e r . < / d i v > ` ;
}
[ "q" , "sort" , "tld" ] . forEach ( ( id ) => $ ( id ) . addEventListener ( "input" , render ) ) ;
document . addEventListener ( "click" , ( e ) => { const b = e . target . closest ( "[data-buy]" ) ; if ( b ) openBuy ( b . dataset . buy ) ; } ) ;
// ---------- buy ----------
function setMsg ( t , cls = "" ) { $ ( "buy-msg" ) . textContent = t ; $ ( "buy-msg" ) . className = "msg " + cls ; }
function push ( t ) { const log = $ ( "buy-steps" ) ; log . className = "steps on" ; const d = document . createElement ( "div" ) ; d . textContent = t ; log . appendChild ( d ) ; log . scrollTop = 1e6 ; }
function openBuy ( name ) {
selected = listings . find ( ( l ) => l . name === name ) ; if ( ! selected ) return ;
$ ( "buy-name" ) . textContent = name ;
2026-09-20 19:20:30 +02:00
const isUsd = selected . kind === "usd" ;
const price = BigInt ( isUsd ? clampSats ( satsForCents ( selected . target _cents ) , selected ) : selected . price _sats ) ;
const check = isUsd ? BNS . verifyUsdListing ( selected ) : BNS . verifyListing ( selected , { category : selected . category } ) ;
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
$ ( "buy-kv" ) . innerHTML = [
2026-09-20 19:20:30 +02:00
isUsd ? [ "Price" , ` ${ esc ( fmtUsdC ( selected . target _cents ) ) } fixed · about ${ esc ( bch ( price ) ) } at today's rate (the exact amount is set by the oracle quote when you buy, between ${ esc ( bch ( selected . floor _sats ) ) } and ${ esc ( bch ( selected . ceil _sats ) ) } ) ` ]
: [ "Price" , ` ${ esc ( bch ( price ) ) } (≈ ${ esc ( usd ( price ) ) } ) ` ] ,
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
[ "Seller" , esc ( selected . seller ) ] ,
[ "You receive" , "the name's certificate, to your token address" ] ,
2026-09-20 19:20:30 +02:00
[ "Offer check" , check . ok ? ( isUsd ? "contract terms verified" : "seller signature valid" ) : "INVALID: " + esc ( check . error ) ] ,
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).
2026-09-20 18:18:43 +02:00
[ "Extra" , "≈ 16 bits dust + fee" ] ,
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
] . 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 ;
$ ( "buy-go" ) . disabled = ! canBuy ; $ ( "buy-go" ) . textContent = "Buy — sign & broadcast" ;
$ ( "buy-signin" ) . hidden = ! ! wallet ;
if ( ! wallet ) setMsg ( "Sign in on the dashboard first — the purchase is signed with your wallet in this browser." ) ;
$ ( "buy" ) . classList . add ( "open" ) ;
}
const closeBuy = ( ) => $ ( "buy" ) . classList . remove ( "open" ) ;
$ ( "buy-close" ) . addEventListener ( "click" , closeBuy ) ; $ ( "buy-cancel" ) . addEventListener ( "click" , closeBuy ) ;
$ ( "buy" ) . addEventListener ( "click" , ( e ) => { if ( e . target === $ ( "buy" ) ) closeBuy ( ) ; } ) ;
$ ( "buy-go" ) . addEventListener ( "click" , async ( ) => {
if ( ! selected || ! wallet ) return ;
const btn = $ ( "buy-go" ) ; btn . disabled = true ; btn . textContent = "Buying…" ; setMsg ( "" ) ;
let el = null ;
try {
el = await BNS . connect ( ) ; push ( "connected to chipnet" ) ;
const utxos = await BNS . getUtxosForAddresses ( el , wallet . watchedAddresses ) ;
push ( ` wallet has ${ utxos . filter ( ( u ) => ! u . token ) . length } spendable coin(s) ` ) ;
2026-09-20 19:20:30 +02:00
let built , signed ;
if ( selected . kind === "usd" ) {
const q = await ( await fetch ( ` ${ API } /api/price/oracle?txid= ${ encodeURIComponent ( selected . outpoint . txid ) } ` , { cache : "no-store" } ) ) . json ( ) ;
if ( ! q . message ) throw new Error ( q . error || "no oracle quote" ) ;
push ( ` oracle quote: 1 BCH = $ ${ ( q . price _cents / 100 ) . toFixed ( 2 ) } (median of ${ q . median _of } exchanges) ` ) ;
built = BNS . buildUsdBuyTx ( { listing : selected , quote : q , buyerAddress : wallet . address , buyerTokenAddress : wallet . tokenAddress , utxos , records : selected . records || { } , addressToLockingBytecode : BNS . addressToLockingBytecode } ) ;
push ( ` you pay ${ bch ( built . priceSats ) } · fee ${ bits ( built . fee ) } ` ) ;
signed = BNS . signInputs ( built . transaction , built . sourceOutputs , ( h ) => wallet . keyFor ( h ) , { skip : [ built . covenantInputIndex ] } ) ;
} else {
built = BNS . completeSale ( { listing : selected , buyerAddress : wallet . address , buyerTokenAddress : wallet . tokenAddress , utxos , records : selected . records || { } , addressToLockingBytecode : BNS . addressToLockingBytecode } ) ;
push ( ` built sale · price ${ bch ( built . costs . priceSats ) } · fee ${ bits ( built . costs . chainFeeSats ) } ` ) ;
signed = BNS . signInputs ( built . transaction , built . sourceOutputs , ( h ) => wallet . keyFor ( h ) , { skip : [ built . sellerInputIndex ] } ) ;
}
feat(bns): name marketplace and TLD-owner co-sign rule
Two gaps the owner panel left open. First, a hidden TLD was only a UI
gate: anyone could still broadcast a REG under it and every indexer
admitted it. Second, there was no way to sell a name without trusting
the other side.
Co-sign rule (consensus, applied in lockstep by bns.js and
resolver-web.js): a REG under a TLD whose records at that height say
policy "cosign" or hidden 1 is indexed only if the transaction carries
the TLD's own certificate. The certificate can only be spent by the
owner's key and is re-issued to them in the same transaction, so it is
a co-signature nobody can forge and nothing is consumed. The TLD map
now keeps the TUPD timeline so policy is evaluated at the REG height.
Owners register under their private TLDs with the certificate added
from their own wallet; third parties under a "cosign" TLD build the
full transaction, sign their inputs and queue it at /api/cosign, where
the owner approves it from the dashboard (signCosignRequest refuses to
sign unless the certificate returns to the same locking script).
Marketplace: a listing is the seller's certificate input plus a price
output signed SIGHASH_SINGLE|ANYONECANPAY, stored by the gateway as a
bulletin board (/api/market, verified against the on-chain owner and
pruned when the certificate moves). The buyer completes it in one
transaction, so the seller is paid exactly when the name moves.
Cancelling also spends the certificate once so the offer is void.
Site: market.html, Sell sub-tab and Pending approvals in the portal,
Market link in nav and footer, six dictionaries extended, cache tags
bumped. Verified on chipnet: cosigned.sc registered by a throwaway
wallet through the queue with the .sc certificate back at the owner;
aloevera.test listed and delisted through the API.
Ariadne's resolver-web.js copy and the mobile Bns.java port still need
the co-sign rule; until then they admit REGs this index rejects.
2026-09-17 04:04:22 +02:00
push ( "signed your inputs (the seller's signature is already in place)" ) ;
const txid = await BNS . broadcast ( el , signed . hex ) ;
push ( "broadcast: " + txid ) ;
setMsg ( ` Done. ${ selected . name } is yours — it appears in your dashboard within a minute. ` , "ok" ) ;
btn . textContent = "Bought ✓" ;
setTimeout ( load , 3000 ) ;
} catch ( e ) {
const raw = String ( e . message || e ) ;
setMsg ( /not enough funds/i . test ( raw ) ? ` Not enough coins: ${ raw } . Fund ${ wallet . address } first. ` : "Failed: " + raw , "err" ) ;
push ( "error: " + raw ) ; btn . disabled = false ; btn . textContent = "Buy — sign & broadcast" ;
} finally { try { el ? . close ? . ( ) ; } catch { } }
} ) ;
( async function boot ( ) {
wallet = await restoreWallet ( ) ;
await load ( ) ;
} ) ( ) ;
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).
2026-09-20 18:18:43 +02:00
window . addEventListener ( "sirius:price" , ( ) => { if ( listings . length ) render ( ) ; } ) ;