2026-07-29 13:54:34 +02:00
|
|
|
// Browser entry point for the registration flow. Everything the register page
|
|
|
|
|
// needs, and nothing that touches the filesystem or a private key we hold.
|
|
|
|
|
//
|
|
|
|
|
// Bundled by build-web.mjs to site/js/bns-register.js as a plain ES module:
|
|
|
|
|
// <script type="module"> import * as BNS from './js/bns-register.js' </script>
|
|
|
|
|
|
|
|
|
|
export { BuiltInWallet, CHIPNET_PREFIX } from "../lib/wallet-web.js";
|
|
|
|
|
export {
|
|
|
|
|
connect,
|
|
|
|
|
checkAvailability,
|
|
|
|
|
quoteRegistration,
|
|
|
|
|
registerWithBuiltInWallet,
|
|
|
|
|
registerWithExternalWallet,
|
2026-09-07 00:18:19 +02:00
|
|
|
registerTldWithBuiltInWallet,
|
2026-09-07 01:39:16 +02:00
|
|
|
registerTldWithExternalWallet,
|
feat(registrar): 90/10 revenue split — TLD owner earns from name mints
Every second-level name registration under a TLD now routes 90% of the
service fee to whoever holds that TLD's certificate on chain, with 10%
going to the platform address. That's the economic incentive for
minting a TLD: you earn from every name registered under it.
The mechanism, end to end:
1. resolver-web.js fetchTldMap now also records mintScriptHex — the
scriptPubKey of the TREG output that carries each TLD's NFT.
Exported so registrar can decode it into a cashaddr with libauth.
MVP: this is the ORIGINAL owner; NFT transfers after mint are not
traced yet (a follow-up will walk the chain of transfers).
2. registrar.js gains findTldOwnerAddress(client, tld) and
splitServiceFee(sats). The split constants live at the top of the
file (TLD_OWNER_SHARE_NUM/DEN = 90/100) so the ratio moves in one
place. Rounding: BigInt division favours the platform on odd sat
counts so the two shares always sum EXACTLY to the input.
3. quoteRegistration wraps the existing flow: it derives the TLD from
the name, looks up the TLD owner, and if the owner ≠ buyer it asks
buildRegistrationTx to add a second fee output. If the owner
couldn't be resolved (TLD not registered, decode failure) the full
fee stays on the platform address — the buyer still pays the same
amount either way.
4. register-tx.js buildRegistrationTx accepts tldFeeAddress/tldFeeSats
and, when set, emits an extra P2PKH output for the TLD owner. Sits
between the beacon dust and the platform-fee output; outputMap
records .tldOwnerFee so callers can find it. costs also carries
tldOwnerFeeSats and netCostSats includes it.
5. priceSummary in registrar-config splits the 'Service fee' row into
'Service fee — TLD owner (90%)' + 'Service fee — platform (10%)'
whenever tldOwnerFeeSats > 0, with a per-line note explaining
where the money goes.
Bundle: re-exported findTldOwnerAddress + splitServiceFee from
register-entry.js. Rebuilt bns-register.js (~34 kB) and deployed;
cache-buster bumped to ?v=20260908split on portal / admin /
register-flow.js.
Verified live: findTldOwnerAddress('.bch') returns the operator
cashaddr; quoteRegistration('tester42.bch') builds cleanly with a
9,000/1,000 split output pair on a 10,000-sat fee; priceSummary
renders both lines. No regressions on the TLD-mint flow (buyer IS
the TLD owner there — split short-circuits and it stays a single
fee output as before).
2026-09-08 02:42:16 +02:00
|
|
|
findTldOwnerAddress,
|
|
|
|
|
splitServiceFee,
|
2026-07-29 13:54:34 +02:00
|
|
|
setRecordsWithBuiltInWallet,
|
|
|
|
|
setRecordsWithExternalWallet,
|
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
|
|
|
setTldRecordsWithBuiltInWallet,
|
|
|
|
|
signRecordsManifest,
|
2026-07-29 13:54:34 +02:00
|
|
|
findCertificateUtxo,
|
|
|
|
|
getBalance,
|
|
|
|
|
} from "../lib/registrar.js";
|
|
|
|
|
export { REGISTRAR, priceSummary } from "../registrar-config.js";
|
|
|
|
|
export {
|
|
|
|
|
buildRegistrationTx,
|
2026-09-07 00:18:19 +02:00
|
|
|
buildTldRegistrationTx,
|
2026-07-29 13:54:34 +02:00
|
|
|
buildUpdateTx,
|
|
|
|
|
buildPrepTx,
|
|
|
|
|
hasGenesisInput,
|
|
|
|
|
toWcTransactionObject,
|
|
|
|
|
normalizeName,
|
2026-09-07 00:18:19 +02:00
|
|
|
normalizeTld,
|
2026-07-29 13:54:34 +02:00
|
|
|
displayName,
|
|
|
|
|
payloadBudget,
|
2026-09-07 00:18:19 +02:00
|
|
|
TLD_BEACON,
|
2026-07-29 13:54:34 +02:00
|
|
|
NoGenesisInputError,
|
|
|
|
|
InsufficientFundsError,
|
|
|
|
|
} from "../lib/register-tx.js";
|
|
|
|
|
export { signTransaction, txidOf, txidOfHex } from "../lib/sign-tx.js";
|
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
|
|
|
export { buildListing, completeSale, verifyListing, signInputs, sourceOutputToJson, sourceOutputFromJson } from "../lib/market-tx.js";
|
|
|
|
|
export { findTldCertificateUtxo, buildCosignRequest, signCosignRequest } from "../lib/registrar.js";
|
feat(market): names can be priced in US dollars — a covenant holds the certificate, a gateway-signed oracle sets the BCH amount
A BCH-priced offer is a signed transaction with a fixed amount, so a
seller who wants "$500" had to relist whenever the rate moved. The new
USD mode moves the certificate into a small CashScript covenant
(contracts/usd-listing.cash). Anyone may buy it by paying the seller
target_cents / price, where the price comes from a message signed by the
gateway's oracle key — the median of five exchanges the site already
uses. The payout is clamped to a floor/ceiling band the seller sets, and
the seller can reclaim the certificate at any time.
What the chain can and cannot enforce, stated plainly in the contract and
the UI: script can require a transaction to be mined no earlier than a
time, never no later, so a quote cannot expire on-chain. The band is the
guarantee, and quotes are bound to the listing's outpoint so cancelling
and relisting voids every quote ever issued. An offline libauth VM test
covers list, buy, underpayment, foreign-listing quotes, forged quotes,
band clamping, cancel and a non-seller cancel; on chipnet aloevera.test
was listed at $0.30, bought by a second wallet for 119,090 sat at
$251.91, listed again by the new owner and cancelled.
Gateway: GET /api/price/oracle[?txid=] serves the oracle public key and
per-listing signed quotes; the key lives in oracle.key beside the
gateway, never in the repo. POST /api/market accepts kind "usd" after
reproducing the redeem script from the stated terms and finding the
certificate in that covenant; such listings are pruned once the covenant
output is spent; DELETE accepts the listing's seller while the index
shows the covenant as holder.
Dashboard: the Sell tab has "Price is fixed in: US dollars / BCH", a
band control with the resulting BCH range, and cancel through the
covenant. Market: USD listings show the dollar price, today's BCH
equivalent and the band; buying fetches a quote and completes the
covenant spend. Studio no longer sends a needless UPD when the registry
view is stale, and missing files on a name now get a real 404 page.
2026-09-20 19:20:46 +02:00
|
|
|
export { usdListingRedeem, usdListingAddress, payoutSats, parseOracleMessage, verifyOracleMessage, buildUsdListingTx, buildUsdBuyTx, buildUsdCancelTx, verifyUsdListing, DEFAULT_MAX_AGE_SECS } from "../lib/market-usd.js";
|
2026-08-31 05:40:47 +02:00
|
|
|
export { toTokenAddress, addressToLockingBytecode, addressToScripthash, getUtxos, getUtxosForAddresses, broadcast } from "../lib/chain.js";
|
2026-07-29 13:54:34 +02:00
|
|
|
export { resolveName, buildIndex } from "../lib/resolver-web.js";
|
|
|
|
|
export {
|
|
|
|
|
describeGenesisRequirement,
|
|
|
|
|
pubkeyToAddress,
|
|
|
|
|
pubkeyToLockingBytecode,
|
|
|
|
|
} from "../lib/connect/wallet-session.js";
|
|
|
|
|
export { binToHex, hexToBin } from "@bitauth/libauth";
|
|
|
|
|
export { stringify } from "@bitauth/libauth";
|
|
|
|
|
|
|
|
|
|
// NOT re-exported here on purpose: the WizardConnect and WalletConnect adapters.
|
|
|
|
|
// They are separate bundles (site/js/wizardconnect.js, site/js/walletconnect2.js)
|
|
|
|
|
// that the page dynamic-imports only when the buyer picks that option.
|
|
|
|
|
// - WizardConnect: LGPL-3.0-or-later, must stay separate + unminified (§4d1).
|
|
|
|
|
// - WalletConnect: ~590 kB nobody using the built-in wallet should download.
|