feat(registrar): registerTldWithExternalWallet + wire into portal
Adds the external-wallet variant of registerTldWithBuiltInWallet so WizardConnect users can mint TLDs from the sirius.x portal without first importing a seed. Same transaction shape (TREG payload, TLD- beacon output, service-fee output) — the wallet approves the mint (and, if needed, a one-time prep signature to satisfy the vout-0 non-token genesis-input rule) on the user's own device. Bundle: re-exported from src/web/register-entry.js and rebuilt (bns-register.js: 33.3 kB, cache-buster bumped to ?v=20260907tldext on portal.html / register.html / admin/index.html). Portal: TLD-register submit now dispatches on wallet.source, calling registerTldWithExternalWallet with wallet.session when the user is signed in via WC. Removed the WC-disable guard and updated the card copy to say TLD mints also go through the wallet's signing prompt. Uses the same landOnChain helper as registerWithExternalWallet, so wallet-broadcasts (walletBroadcasts:true sessions) and duplicate/ mempool responses are handled identically.
This commit is contained in:
parent
d07fece6c9
commit
db71b9e832
2 changed files with 105 additions and 0 deletions
|
|
@ -293,6 +293,110 @@ export async function registerTldWithBuiltInWallet(client, {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TLD with an EXTERNAL wallet (WizardConnect).
|
||||
*
|
||||
* Same transaction shape as registerTldWithBuiltInWallet — same TREG payload,
|
||||
* same TLD-beacon output, same service-fee output — only the signing transport
|
||||
* differs. Genesis-input requirement is handled by prompting the connected
|
||||
* wallet for a one-time prep signature if it can't front a vout-0 non-token
|
||||
* coin already, mirroring registerWithExternalWallet's pattern.
|
||||
*
|
||||
* Does NOT accept `ownerAddress` because a TLD certificate is minted to
|
||||
* whoever signs the mint — using the first address the connected wallet
|
||||
* exposes keeps the same "you own what you signed for" invariant as the
|
||||
* name-registration external path.
|
||||
*
|
||||
* @param {object} o.session a WalletSession (see connect/)
|
||||
*/
|
||||
export async function registerTldWithExternalWallet(client, {
|
||||
session,
|
||||
tld,
|
||||
records = {},
|
||||
serviceFee = { address: null, sats: 0n },
|
||||
feeRate = REGISTRAR.feeRate,
|
||||
tldListUrl = null,
|
||||
onProgress = () => {},
|
||||
}) {
|
||||
const rawTld = normalizeTld(tld);
|
||||
onProgress("checking-availability");
|
||||
if (tldListUrl) {
|
||||
try {
|
||||
const r = await fetch(tldListUrl);
|
||||
if (r.ok) {
|
||||
const j = await r.json();
|
||||
const taken = Array.isArray(j.tlds) && j.tlds.some((t) => (t.tld || t) === rawTld);
|
||||
if (taken) throw new Error(`".${rawTld}" is already registered as a TLD`);
|
||||
}
|
||||
} catch (e) {
|
||||
if (/already registered/.test(e.message)) throw e;
|
||||
// network / API blip — proceed; on-chain "first TREG wins" handles it.
|
||||
}
|
||||
}
|
||||
|
||||
onProgress("reading-wallet");
|
||||
const addresses = await session.getAddresses();
|
||||
if (!addresses.length) throw new Error("the wallet exposed no addresses");
|
||||
const owner = addresses[0];
|
||||
|
||||
onProgress("loading-coins");
|
||||
let utxos = await getUtxosForAddresses(client, addresses);
|
||||
if (utxos.filter((u) => !u.token).reduce((s, u) => s + u.satoshis, 0n) === 0n) {
|
||||
throw new Error("the connected wallet has no spendable coins");
|
||||
}
|
||||
|
||||
let prepTxid = null;
|
||||
if (!hasGenesisInput(utxos)) {
|
||||
onProgress("preparing-wallet");
|
||||
const prep = buildPrepTx({ ownerAddress: owner, utxos, feeRate, addressToLockingBytecode });
|
||||
const prepSigned = await session.signTransaction(prep, {
|
||||
userPrompt: "One-time setup so your wallet can create a TLD certificate",
|
||||
});
|
||||
prepTxid = await landOnChain(client, session, prepSigned, onProgress);
|
||||
onProgress("prepared", { txid: prepTxid });
|
||||
utxos = [
|
||||
{
|
||||
txid: prepTxid, vout: 0,
|
||||
satoshis: prep.transaction.outputs[0].valueSatoshis,
|
||||
address: owner,
|
||||
lockingBytecode: addressToLockingBytecode(owner),
|
||||
},
|
||||
...utxos.filter((u) => !u.token && !prep.inputUtxos.some((i) => i.txid === u.txid && i.vout === u.vout)),
|
||||
];
|
||||
}
|
||||
|
||||
onProgress("building");
|
||||
const built = buildTldRegistrationTx({
|
||||
tld: rawTld,
|
||||
ownerAddress: owner,
|
||||
ownerTokenAddress: toTokenAddress(owner),
|
||||
changeAddress: owner,
|
||||
records,
|
||||
utxos,
|
||||
feeAddress: serviceFee.address || null,
|
||||
feeSats: BigInt(serviceFee.sats ?? 0n),
|
||||
feeRate,
|
||||
addressToLockingBytecode,
|
||||
});
|
||||
|
||||
onProgress("awaiting-approval");
|
||||
const signed = await session.signTransaction(built, {
|
||||
userPrompt: `Register .${rawTld} — the TLD certificate is minted to your own address`,
|
||||
});
|
||||
const txid = await landOnChain(client, session, signed, onProgress);
|
||||
|
||||
onProgress("registered", { txid, category: built.category });
|
||||
return {
|
||||
tld: built.tld,
|
||||
category: built.category,
|
||||
txid,
|
||||
prepTxid,
|
||||
ownerAddress: owner,
|
||||
certificateAddress: toTokenAddress(owner),
|
||||
costs: built.costs,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mint a name certificate on a buyer's behalf, from the registrar's own coins.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export {
|
|||
registerWithBuiltInWallet,
|
||||
registerWithExternalWallet,
|
||||
registerTldWithBuiltInWallet,
|
||||
registerTldWithExternalWallet,
|
||||
setRecordsWithBuiltInWallet,
|
||||
setRecordsWithExternalWallet,
|
||||
findCertificateUtxo,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue