Every client hard-coded the chipnet beacons, address prefix and electrum servers on its own: resolver, registrar config, wallets, gateway, indexer, mirror scripts, the browser bundle and the mobile Java. A mainnet launch would have meant finding all of them and hoping none was missed. The table now lives in resolver-web.js, the one file every client already shares, so it stays a single-file drop-in. BNS_NETWORK selects the record; unset means chipnet, so nothing changes today: the live index resolves the same 60 names and 20 TLDs, the 67 offline tests pass, and the dashboard, market and studio load the same values through BNS.NETWORK. The mainnet record carries the verified public servers, the prefix and its own Sia bucket, but its beacons, start height and operator address are deliberately null: requireBeacons() refuses to scan until they are pinned in the order ROADMAP-MAINNET.md §6 requires. Bns.java reads a generated BnsNetwork.java so the phone cannot drift from the desktop clients. NETWORK-CONFIG.md records what reads the table and what a launch still pins.
7 lines
60 KiB
JavaScript
7 lines
60 KiB
JavaScript
import{generateBip39Mnemonic as Bn,deriveSeedFromBip39Mnemonic as Ae,deriveHdPrivateNodeFromSeed as In,deriveHdPath as Pn,secp256k1 as Be,hash160 as Nn,encodeCashAddress as ss,lockingBytecodeToCashAddress as Rn,cashAddressToLockingBytecode as rs,binToHex as Ln,hexToBin as is,utf8ToBin as Ne,binToBase64 as Yt,base64ToBin as Vt}from"@bitauth/libauth";var kt={chipnet:{id:"chipnet",label:"chipnet",prefix:"bchtest",beacon:"bchtest:qp8njaa9a3ahg7259s5qajnce526n0rttsq8qwx4jl",beaconScripthash:"e1cdbba719436f49acb4bf245b44df875c6d6b405eda46a9d3e736d138102f3b",tldBeacon:"bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh",tldBeaconScripthash:"c85db10e106606273422b2733b2a6fb8b35a4d0e7dbfb20cf59bdb0833c008b8",electrum:[{url:"wss://silentmode.st/electrum",ip:"195.184.247.106"},{url:"wss://coinspectrum.duckdns.org:50011",ip:"195.184.247.106"},{url:"wss://chipnet.bch.ninja:50004",ip:"135.148.236.244"},{url:"wss://chipnet.imaginary.cash:50004",ip:"66.29.152.199"},{url:"wss://tbch4.loping.net:62002",ip:"183.89.202.207"}],beaconOnly:/silentmode\.st\/electrum|coinspectrum\.duckdns\.org:50011/,electrumListName:"electrum.bch",rootTldName:"tlds.bch",bootstrapTlds:["bch"],startHeight:2e5,hostingBucket:"bns",nameListUrl:"https://s3.silentmode.st:8600/bns/name-list.json",cdnIndexUrl:"https://dl.silentmode.st/bns-name-index.json",nostrTags:{names:"bns-name-list",tlds:"bns-tld-list"},explorerTx:"https://chipnet.imaginary.cash/tx/",faucets:[{name:"tbch.googol.cash",url:"https://tbch.googol.cash/"},{name:"chipnet.bch.ninja faucet",url:"https://chipnet.bch.ninja/faucet"}],operatorAddress:"bchtest:qzew3dqcsj0guwe5y3uxf9q2xs5ajgy9lca4z093cu",accountPath:"m/44'/145'/0'",bchnRpcPort:48332},mainnet:{id:"mainnet",label:"mainnet",prefix:"bitcoincash",beacon:null,beaconScripthash:null,tldBeacon:null,tldBeaconScripthash:null,electrum:[{url:"wss://bch.imaginary.cash:50004",ip:"67.223.119.97"},{url:"wss://electrum.imaginary.cash:50004",ip:"15.204.113.162"},{url:"wss://electroncash.dk:50004",ip:"87.63.200.138"},{url:"wss://bch.loping.net:50004",ip:"183.89.202.207"},{url:"wss://bch.soul-dev.com:50004",ip:"174.141.196.204"},{url:"wss://cashnode.bch.ninja:50004",ip:"135.148.236.246"}],beaconOnly:/(?!)/,electrumListName:"electrum.bch",rootTldName:"tlds.bch",bootstrapTlds:["bch"],startHeight:null,hostingBucket:"bns-mainnet",nameListUrl:"https://s3.silentmode.st:8600/bns-mainnet/name-list.json",cdnIndexUrl:"https://dl.silentmode.st/bns-mainnet-name-index.json",nostrTags:{names:"bns-mainnet-name-list",tlds:"bns-mainnet-tld-list"},explorerTx:"https://blockchair.com/bitcoin-cash/transaction/",faucets:[],operatorAddress:null,accountPath:"m/44'/145'/0'",bchnRpcPort:8332}},Se="chipnet";function gn(){let t=typeof globalThis<"u"?globalThis.BNS_NETWORK:null,e=typeof process<"u"&&process.env?process.env.BNS_NETWORK:null;return String(t||e||Se).trim().toLowerCase()}function Pt(t){if(t&&typeof t=="object")return t;let e=t||gn(),n=kt[e];if(!n)throw new Error(`unknown network "${e}" (known: ${Object.keys(kt).join(", ")})`);return n}var T=Pt();function zt(t=T){let e=Pt(t);if(!e.beaconScripthash||!e.tldBeaconScripthash)throw new Error(`${e.label}: beacon addresses are not pinned yet (see ROADMAP-MAINNET.md \xA76)`);return e}var jo=T.beacon,Yo=T.beaconScripthash,Vo=T.tldBeacon,Xo=T.tldBeaconScripthash,Jo=T.electrum,Qo=kt.chipnet.electrum,Zo=T.electrumListName,ke="BNS1";var Te="bch",mn=/^[a-z0-9-]{1,32}$/,Ee=/^[a-z0-9-]{1,16}$/,yn=/^[a-z0-9-]{1,32}(\.[a-z0-9-]{1,16})?$/;function wn(t){return t.includes(".")?t:t+"."+Te}var xn=t=>{let e=new Uint8Array(t.length/2);for(let n=0;n<e.length;n++)e[n]=parseInt(t.substr(n*2,2),16);return e},qt=t=>[...new TextEncoder().encode(t)].map(e=>e.toString(16).padStart(2,"0")).join("");function kn(t){let n=String(t).toLowerCase().trim().replace(/^[a-z]+:\/\//,"").split("/")[0].replace(/\.$/,"").split(".").filter(Boolean);if(n.length===0)throw new Error(`invalid name "${t}"`);let o,s;if(n.length===1?(o=n[0],s=Te):(s=n[n.length-1],o=n[n.length-2]),!mn.test(o)||!Ee.test(s))throw new Error(`invalid name "${t}" (allowed: <label>.<tld>, [a-z0-9-])`);return`${o}.${s}`}var It=class{constructor(e,n,o){this.url=e,this.WS=n||globalThis.WebSocket,this.options=o,this.id=0,this.pending=new Map,this.buf=""}connect(){return new Promise((e,n)=>{let o=this.options?new this.WS(this.url,this.options):new this.WS(this.url);this.ws=o;let s=async()=>{try{await this.call("server.version",["bns-web","1.4.2"]),e(this)}catch(i){n(i)}},r=i=>n(new Error("electrum ws error: "+(i?.message||this.url))),a=i=>this._onData(typeof i.data=="string"?i.data:i.data.toString());o.addEventListener?(o.addEventListener("open",s),o.addEventListener("error",r),o.addEventListener("message",a)):(o.onopen=s,o.onerror=r,o.onmessage=a)})}_handle(e){let n=this.pending.get(e.id);n&&(this.pending.delete(e.id),e.error?n.reject(new Error(JSON.stringify(e.error))):n.resolve(e.result))}_onData(e){this.buf+=e;let n;for(;(n=this.buf.indexOf(`
|
|
`))>=0;){let s=this.buf.slice(0,n).trim();if(this.buf=this.buf.slice(n+1),s)try{this._handle(JSON.parse(s))}catch{}}let o=this.buf.trim();if(o)try{let s=JSON.parse(o);this._handle(s),this.buf=""}catch{}}call(e,n=[]){let o=++this.id;return new Promise((s,r)=>{this.pending.set(o,{resolve:s,reject:r}),this.ws.send(JSON.stringify({id:o,method:e,params:n})+`
|
|
`),setTimeout(()=>{this.pending.has(o)&&(this.pending.delete(o),r(new Error(`electrum timeout: ${e}`)))},2e4)})}close(){try{this.ws.close()}catch{}}},bn=t=>typeof t=="string"?{url:t}:t;async function Sn(t,e,{directIP:n=!1}={}){let o;for(let s of t){let r=bn(s);try{return await new It(r.url,e).connect()}catch(a){o=a}if(n&&r.ip)try{let a=new URL(r.url),i=`${a.protocol}//${r.ip}:${a.port}`;return await new It(i,e,{servername:a.hostname}).connect()}catch(a){o=a}}throw o??new Error("no electrum server reachable")}function _e(t){if(!t||!t.startsWith("6a"))return null;let e=xn(t),n=1,o=[];for(;n<e.length;){let r=e[n++],a;if(r<=75)a=r;else if(r===76)a=e[n++];else if(r===77)a=e[n]|e[n+1]<<8,n+=2;else return null;o.push(e.slice(n,n+a)),n+=a}let s=new TextDecoder().decode(o[0]??new Uint8Array);if(!s.startsWith(ke))return null;try{let r=JSON.parse(s.slice(ke.length));if(Tn.has(r.o)&&typeof r.n=="string")return r}catch{}return null}var Tn=new Set(["REG","UPD","TREG","TUPD"]);function Oe(t,e){let n=t.height>0?t.height:1/0,o=e.height>0?e.height:1/0;return n-o||t.tx_hash.localeCompare(e.tx_hash)}function ve(t,e){let n=new Set(t.map(i=>i.tx_hash)),o=new Map(t.map(i=>{let l=new Set;for(let c of e.get(i.tx_hash)?.vin??[])c.txid&&c.txid!==i.tx_hash&&n.has(c.txid)&&l.add(c.txid);return[i.tx_hash,l]})),s=new Set,r=[],a=[...t];for(;a.length;){let i=a.findIndex(c=>[...o.get(c.tx_hash)].every(h=>s.has(h)));i<0&&(i=0);let[l]=a.splice(i,1);s.add(l.tx_hash),r.push(l)}return r}function Gt(t){let e=t.lastIndexOf(".");return e<0?t:t.slice(e+1)}function En(t,e,n){let o=n.get(t);return o?o.regHeight>0&&e>0?o.regHeight<=e:!0:!1}async function jt(t,e=T){let{tldBeaconScripthash:n}=zt(e),o=typeof t.unionHistory=="function"?(await t.unionHistory(n)).history:await t.call("blockchain.scripthash.get_history",[n]);o.sort(Oe);let s=new Map;for(let{tx_hash:a}of o)try{s.set(a,await t.call("blockchain.transaction.get",[a,!0]))}catch{}let r=new Map;for(let{tx_hash:a,height:i}of ve(o.filter(l=>s.has(l.tx_hash)),s)){let c=s.get(a).vout||[],h=null;for(let d of c)h=_e(d.scriptPubKey?.hex)??h;if(!h||typeof h.n!="string"||!Ee.test(h.n))continue;let u=h.n;if(h.o==="TREG"){if(r.has(u))continue;let d=qt(u),p=c.find(m=>m.tokenData?.nft&&m.tokenData.nft.commitment===d);if(!p)continue;r.set(u,{category:p.tokenData.category,regHeight:i,regTxid:a,mintScriptHex:p.scriptPubKey?.hex??null,records:h.r??{},updates:[{height:i,txid:a,records:h.r??{}}]})}else if(h.o==="TUPD"){let d=r.get(u);if(!d||!c.some(p=>p.tokenData&&p.tokenData.category===d.category))continue;d.records=h.r??{},d.updates.push({height:i,txid:a,records:d.records})}}return r}function _n(t,e){if(!t)return{};let n=t.updates||[];if(!n.length)return t.records||{};let o={};for(let s of n)e>0&&(s.height<=0||s.height>e)||(o=s.records||{});return o}function On(t,e){let n=_n(t,e);return n.policy==="cosign"||n.hidden===1||n.hidden===!0||n.hidden==="1"}function vn(t,e,n){let o=qt(n);return(t||[]).some(s=>s.tokenData&&s.tokenData.category===e.category&&s.tokenData.nft&&s.tokenData.nft.commitment===o)}function be(t){if(!t||!t.scriptPubKey)return null;let e=t.scriptPubKey;return typeof e.address=="string"?e.address:Array.isArray(e.addresses)&&e.addresses.length?e.addresses[0]:null}async function bt({network:t=T,electrum:e=Pt(t).electrum,WebSocket:n,client:o,directIP:s=!1,enforceTld:r=!1,cosignGate:a=!0}={}){let i=zt(t),l=o??await Sn(e,n,{directIP:s});try{let c=null;if(r||a)try{c=await jt(l,i)}catch(m){if(r)throw m;c=null}let h=null,u;if(typeof l.unionHistory=="function"){let m=await l.unionHistory(i.beaconScripthash);u=m.history,h={servers:m.servers,unreachable:m.unreachable,disagreements:m.disagreements}}else u=await l.call("blockchain.scripthash.get_history",[i.beaconScripthash]);u.sort(Oe);let d=new Map;for(let{tx_hash:m}of u)try{d.set(m,await l.call("blockchain.transaction.get",[m,!0]))}catch{}let p=new Map;for(let{tx_hash:m,height:f}of ve(u.filter(g=>d.has(g.tx_hash)),d)){let y=d.get(m).vout||[],w=null;for(let S of y)w=_e(S.scriptPubKey?.hex)??w;if(!w)continue;let x=w.n;if(!yn.test(x))continue;let _=wn(x);if(w.o==="REG"){if(p.has(_)||r&&!En(Gt(_),f,c))continue;if(a&&c){let O=c.get(Gt(_));if(O&&On(O,f)&&!vn(y,O,Gt(_)))continue}let S=qt(x),k=y.find(O=>O.tokenData?.nft&&O.tokenData.nft.commitment===S);if(!k)continue;p.set(_,{name:_,category:k.tokenData.category,records:w.r??{},txid:m,height:f,updatedTxid:null,owner:be(k)})}else if(w.o==="UPD"){let S=p.get(_);if(!S)continue;let k=y.find(O=>O.tokenData&&O.tokenData.category===S.category);if(!k)continue;S.records=w.r??{},S.updatedTxid=m,S.owner=be(k)??S.owner}}return h&&Object.defineProperty(p,"integrity",{value:h,enumerable:!1}),p}finally{o||l.close()}}async function An(t,e={}){let n=kn(t);return(await bt(e)).get(n)??null}var ts=T.rootTldName,es=T.bootstrapTlds.slice();var Dn="bchtest",Cn="bitcoincash",At=T.prefix,Xt="m/44'/145'/0'",Un=5,Nt="bns.wallet.v1";function Re(t){let e=Nn(t);return Uint8Array.from([118,169,20,...e,136,172])}function Ie(t,e,n){let o=Rn({bytecode:Re(t),prefix:e,tokenSupport:n});if(typeof o=="string")throw new Error(`address encoding failed: ${o}`);return o.address}var Jt=class t{constructor(e,n,o=At,s=Xt){this.mnemonic=e,this.prefix=o,this.accountPath=s,this._root=In(n),this._keys=new Map,this._derive()}static async create(e=At,n=Xt){let o=Bn();return new t(o,await Ae(o),e,n)}static async fromMnemonic(e,n=At,o=Xt){let s=String(e).trim().toLowerCase().replace(/\s+/g," "),r=await Ae(s);if(typeof r=="string")throw new Error(`invalid recovery phrase: ${r}`);return new t(s,r,n,o)}_derive(){this.receive=[],this.change=[];for(let[e,n]of[[0,this.receive],[1,this.change]])for(let o=0;o<Un;o++){let s=`${this.accountPath}/${e}/${o}`,r=Pn(this._root,s);if(typeof r=="string")throw new Error(`HD derivation failed at ${s}: ${r}`);let a=Be.derivePublicKeyCompressed(r.privateKey);if(typeof a=="string")throw new Error(`pubkey derivation failed: ${a}`);let i=Re(a),l={path:s,branch:e,index:o,privateKey:r.privateKey,publicKey:a,lockingBytecode:i,address:Ie(a,this.prefix,!1),tokenAddress:Ie(a,this.prefix,!0)};n.push(l),this._keys.set(Ln(i),l)}}get address(){return this.receive[0].address}get tokenAddress(){return this.receive[0].tokenAddress}get watchedAddresses(){return[...this.receive,...this.change].map(e=>e.address)}keyFor(e){let n=this._keys.get(e);return n?{privateKey:n.privateKey,publicKey:n.publicKey}:null}signMessage(e,n){if(!(e instanceof Uint8Array)||e.length!==32)throw new Error("signMessage expects a 32-byte Uint8Array digest");let o=n||this.address,s=[...this.receive,...this.change].find(h=>h.address===o);if(!s)throw new Error(`no key for address ${o}`);let r=Be.signMessageHashRecoverableCompact(s.privateKey,e);if(typeof r=="string")throw new Error(`signMessage failed: ${r}`);let{signature:a}=r,i=r.recoveryId??r.recovery;if(typeof i!="number")throw new Error("signMessage: no recovery id in signature result");let l=31+i,c=new Uint8Array(65);return c[0]=l,c.set(a,1),c}async encrypt(e){let n=crypto.getRandomValues(new Uint8Array(16)),o=crypto.getRandomValues(new Uint8Array(12)),s=await Pe(e,n),r=new Uint8Array(await crypto.subtle.encrypt({name:"AES-GCM",iv:o},s,Ne(this.mnemonic)));return JSON.stringify({v:1,kdf:"PBKDF2-SHA256",iterations:Qt,prefix:this.prefix,salt:Yt(n),iv:Yt(o),ct:Yt(r)})}static async decrypt(e,n){let o=typeof e=="string"?JSON.parse(e):e,s=await Pe(n,Vt(o.salt),o.iterations??Qt),r;try{r=await crypto.subtle.decrypt({name:"AES-GCM",iv:Vt(o.iv)},s,Vt(o.ct))}catch{throw new Error("wrong password")}return t.fromMnemonic(new TextDecoder().decode(r),o.prefix??At)}async save(e,n=globalThis.localStorage){n.setItem(Nt,await this.encrypt(e))}static async load(e,n=globalThis.localStorage){let o=n.getItem(Nt);return o?t.decrypt(o,e):null}static exists(e=globalThis.localStorage){return!!e?.getItem(Nt)}static forget(e=globalThis.localStorage){e.removeItem(Nt)}},Qt=25e4;async function Pe(t,e,n=Qt){let o=await crypto.subtle.importKey("raw",Ne(String(t)),"PBKDF2",!1,["deriveKey"]);return crypto.subtle.deriveKey({name:"PBKDF2",salt:e,iterations:n,hash:"SHA-256"},o,{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}var us=kt.chipnet.electrum.map(t=>t.url),Rt=T.electrum.map(t=>t.url),Zt=class{constructor(e,n){this.url=e,this.WS=n||globalThis.WebSocket,this.id=0,this.pending=new Map,this.buf=""}connect(){return new Promise((e,n)=>{let o=new this.WS(this.url);this.ws=o;let s=async()=>{try{await this.call("server.version",["bns-web","1.4.2"]),e(this)}catch(i){n(i)}},r=i=>n(new Error("electrum ws error: "+(i?.message||this.url))),a=i=>this._onData(typeof i.data=="string"?i.data:i.data.toString());o.addEventListener?(o.addEventListener("open",s),o.addEventListener("error",r),o.addEventListener("message",a)):(o.onopen=s,o.onerror=r,o.onmessage=a)})}_handle(e){let n=this.pending.get(e.id);n&&(this.pending.delete(e.id),e.error?n.reject(new Error(JSON.stringify(e.error))):n.resolve(e.result))}_onData(e){this.buf+=e;let n;for(;(n=this.buf.indexOf(`
|
|
`))>=0;){let s=this.buf.slice(0,n).trim();if(this.buf=this.buf.slice(n+1),s)try{this._handle(JSON.parse(s))}catch{}}let o=this.buf.trim();if(o)try{let s=JSON.parse(o);this._handle(s),this.buf=""}catch{}}call(e,n=[]){let o=++this.id;return new Promise((s,r)=>{this.pending.set(o,{resolve:s,reject:r}),this.ws.send(JSON.stringify({id:o,method:e,params:n})+`
|
|
`),setTimeout(()=>{this.pending.has(o)&&(this.pending.delete(o),r(new Error(`electrum timeout: ${e}`)))},2e4)})}close(){try{this.ws.close()}catch{}}};async function Le(t=Rt,e){let n=[];for(let o of t)try{return await new Zt(o,e).connect()}catch(s){n.push(`${o}: ${s?.message??s}`)}throw Fn(t.length,n)}function Fn(t,e){let n=new Error(`no electrum server reachable (tried ${t}). These use non-standard ports, which some networks and VPNs block:
|
|
${e.join(`
|
|
`)}`);return n.code="NO_ELECTRUM",n.failures=e,n}import{cashAddressToLockingBytecode as $n,lockingBytecodeToCashAddress as Mn,sha256 as Hn,hash160 as ps,binToHex as Kn,hexToBin as fs}from"@bitauth/libauth";function De(t){return Kn(Hn.hash(t).slice().reverse())}function L(t){let e=$n(t);if(typeof e=="string")throw new Error(`bad address "${t}": ${e}`);return e.bytecode}function Wn(t){return De(L(t))}function z(t){let e=L(t),n=String(t).includes(":")?t.split(":")[0]:T.prefix,o=Mn({bytecode:e,prefix:n,tokenSupport:!0});if(typeof o=="string")throw new Error(`cannot token-encode "${t}": ${o}`);return o.address}async function Ce(t,e){let n=L(e),o=De(n);return(await t.call("blockchain.scripthash.listunspent",[o,"include_tokens"])).map(r=>({txid:r.tx_hash,vout:r.tx_pos,satoshis:BigInt(r.value),height:r.height,address:e,lockingBytecode:n,token:r.token_data?{category:r.token_data.category,amount:BigInt(r.token_data.amount??0),nft:r.token_data.nft?{capability:r.token_data.nft.capability,commitment:r.token_data.nft.commitment}:void 0}:void 0}))}async function j(t,e){let n=[];for(let o of e)n.push(...await Ce(t,o));return n}async function st(t,e){return t.call("blockchain.transaction.broadcast",[e])}import{binToHex as Dt,hexToBin as X,utf8ToBin as ft,binToUtf8 as Ue,encodeTransaction as Gn,decodeTransaction as ws}from"@bitauth/libauth";var zn="BNS1",dt=T.beacon,ne=T.tldBeacon,B=600n,N=1000n,W=546n,te="bch",ee=200,qn=/^[a-z0-9-]{1,32}$/,Fe=/^[a-z0-9-]{1,16}$/;function Tt(t){let e=String(t).toLowerCase().trim().replace(/^\.+/,"").replace(/\.+$/,"");if(!Fe.test(e))throw new Error(`invalid TLD "${t}" (allowed: [a-z0-9-]{1,16})`);return e}var Lt=class extends Error{constructor(e){super(e),this.name="NoGenesisInputError",this.code="NO_GENESIS_INPUT"}},J=class extends Error{constructor(e,{needSats:n,haveSats:o}={}){super(e),this.name="InsufficientFundsError",this.code="INSUFFICIENT_FUNDS",this.needSats=n,this.haveSats=o}};function H(t){let e=String(t).toLowerCase().trim().replace(/\.$/,"").split(".").filter(Boolean),n,o;if(e.length===0)throw new Error(`invalid name "${t}"`);if(e.length===1?(n=e[0],o=te):(o=e[e.length-1],n=e[e.length-2]),!qn.test(n)||!Fe.test(o))throw new Error(`invalid name "${t}" (allowed: <label>.<tld>, [a-z0-9-])`);return o===te?n:`${n}.${o}`}function Q(t){return t.includes(".")?t:`${t}.${te}`}function Z(t,e,n){let o=JSON.stringify({o:t,n:e,r:n??{}}),s=ft(zn+o);if(s.length>ee)throw new Error(`records too large (${s.length} > ${ee} bytes)`);return s}function oe(t,e="REG"){return ee-Z(e,t,{}).length}function jn(t){return t.length<=75?Uint8Array.from([t.length,...t]):t.length<=255?Uint8Array.from([76,t.length,...t]):Uint8Array.from([77,t.length&255,t.length>>8&255,...t])}function et(t){return Uint8Array.from([106,...jn(t)])}function se(){return Uint8Array.from([65,...new Uint8Array(65),33,...new Uint8Array(33)])}var Yn=t=>!t.token;function M(t,e,{requireGenesis:n=!0}={}){let o=t.filter(Yn),s=[],r=0n;if(n){let i=o.filter(l=>l.vout===0).sort((l,c)=>c.satoshis>l.satoshis?1:-1);if(i.length===0)throw new Lt("wallet has no coin at output index 0, which CashTokens requires to create a new certificate category \u2014 send a small amount to yourself first (buildPrepTx)");s.push(i[0]),r+=i[0].satoshis}let a=o.filter(i=>!s.some(l=>l.txid===i.txid&&l.vout===i.vout)).sort((i,l)=>l.satoshis>i.satoshis?1:-1);for(let i of a){if(r>=e)break;s.push(i),r+=i.satoshis}return{inputs:s,totalSats:r}}function gt(t){return{outpointTransactionHash:X(t.txid),outpointIndex:t.vout,sequenceNumber:4294967294,unlockingBytecode:se()}}function St(t){return{...gt(t),lockingBytecode:t.lockingBytecode,valueSatoshis:t.satoshis,...t.token?{token:{amount:t.token.amount??0n,category:X(t.token.category),...t.token.nft?{nft:{capability:t.token.nft.capability,commitment:X(t.token.nft.commitment||"")}}:{}}}:{}}}function ut(t){return Gn(t).length}function re({name:t,ownerAddress:e,ownerTokenAddress:n,changeAddress:o,records:s={},utxos:r,feeAddress:a=null,feeSats:i=0n,tldFeeAddress:l=null,tldFeeSats:c=0n,beaconAddress:h=dt,feeRate:u=1,addressToLockingBytecode:d,cosignUtxo:p=null,cosignTokenAddress:m=null}){if(typeof d!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let f=H(t),g=Z("REG",f,s),y=BigInt(i??0n),w=BigInt(c??0n);if(p&&!p.token?.nft)throw new Error("cosignUtxo does not carry a TLD certificate");let x=p?BigInt(p.satoshis):0n,_=p?d(m??n??e):null;if(y>0n&&!a)throw new Error("feeSats set but feeAddress missing");if(w>0n&&!l)throw new Error("tldFeeSats set but tldFeeAddress missing");let S=d(o??e),k=d(n??e),O=d(h),I=y>0n?d(a):null,b=w>0n?d(l):null,R=N+B+y+w+x,A=M(r,R+300n-x),v=0n,E=0n,C=!0;for(let P=0;P<6;P++){let{inputs:F}=A,$=p?[...F,p]:F,K=A.totalSats+x,ct=$[0],ot=X(ct.txid),q=(wt,xt)=>{let V=[];return wt&&V.push({lockingBytecode:S,valueSatoshis:xt}),V.push({lockingBytecode:k,valueSatoshis:N,token:{amount:0n,category:ot,nft:{capability:"none",commitment:ft(f)}}}),V.push({lockingBytecode:et(g),valueSatoshis:0n}),V.push({lockingBytecode:O,valueSatoshis:B}),b&&V.push({lockingBytecode:b,valueSatoshis:w}),I&&V.push({lockingBytecode:I,valueSatoshis:y}),p&&V.push({lockingBytecode:_,valueSatoshis:x,token:{amount:BigInt(p.token.amount??0),category:X(p.token.category),nft:{capability:p.token.nft.capability,commitment:X(p.token.nft.commitment||"")}}}),{version:2,locktime:0,inputs:$.map(gt),outputs:V}},hn=q(!0,1000000n),pn=ut(hn);v=BigInt(Math.ceil(pn*u));let vt=R+v;if(K<vt){let wt=M(r,vt+200n-x);if(wt.inputs.length>F.length){A=wt;continue}throw new J(`not enough funds: need ${vt} sat, have ${K} sat`,{needSats:vt,haveSats:K})}if(E=K-vt,C=E>=W,!C){let wt=q(!1,0n);v=K-R;let xt=BigInt(Math.ceil(ut(wt)*u));if(v<xt){let V=M(r,R+xt+W+200n-x);if(V.inputs.length>F.length){A=V;continue}throw new J(`not enough funds: need ${R+xt} sat, have ${K} sat`,{needSats:R+xt,haveSats:K})}E=0n}let fn=q(C,E),lt={},pt=0;return C&&(lt.change=pt++),lt.certificate=pt++,lt.opReturn=pt++,lt.beacon=pt++,b&&(lt.tldOwnerFee=pt++),I&&(lt.serviceFee=pt++),p&&(lt.cosignCertificate=pt++),{name:f,displayName:Q(f),category:Dt(ot),transaction:fn,sourceOutputs:$.map(St),inputUtxos:$,outputMap:lt,payload:g,costs:{certificateDustSats:N,beaconDustSats:B,serviceFeeSats:y,tldOwnerFeeSats:w,chainFeeSats:v,changeSats:E,totalInputSats:K,netCostSats:y+w+v+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function Ct({tld:t,ownerAddress:e,ownerTokenAddress:n,changeAddress:o,records:s={},utxos:r,feeAddress:a=null,feeSats:i=0n,beaconAddress:l=ne,feeRate:c=1,addressToLockingBytecode:h}){if(typeof h!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let u=Tt(t),d=Z("TREG",u,s),p=BigInt(i??0n);if(p>0n&&!a)throw new Error("feeSats set but feeAddress missing");let m=h(o??e),f=h(n??e),g=h(l),y=p>0n?h(a):null,w=N+B+p,x=M(r,w+300n),_=0n,S=0n,k=!0;for(let O=0;O<6;O++){let{inputs:I,totalSats:b}=x,R=I[0],A=X(R.txid),v=(ct,ot)=>{let q=[];return ct&&q.push({lockingBytecode:m,valueSatoshis:ot}),q.push({lockingBytecode:f,valueSatoshis:N,token:{amount:0n,category:A,nft:{capability:"none",commitment:ft(u)}}}),q.push({lockingBytecode:et(d),valueSatoshis:0n}),q.push({lockingBytecode:g,valueSatoshis:B}),y&&q.push({lockingBytecode:y,valueSatoshis:p}),{version:2,locktime:0,inputs:I.map(gt),outputs:q}},E=v(!0,1000000n),C=ut(E);_=BigInt(Math.ceil(C*c));let P=w+_;if(b<P){let ct=M(r,P+200n);if(ct.inputs.length>I.length){x=ct;continue}throw new J(`not enough funds: need ${P} sat, have ${b} sat`,{needSats:P,haveSats:b})}if(S=b-P,k=S>=W,!k){let ct=v(!1,0n);_=b-w;let ot=BigInt(Math.ceil(ut(ct)*c));if(_<ot){let q=M(r,w+ot+W+200n);if(q.inputs.length>I.length){x=q;continue}throw new J(`not enough funds: need ${w+ot} sat, have ${b} sat`,{needSats:w+ot,haveSats:b})}S=0n}let F=v(k,S),$={},K=0;return k&&($.change=K++),$.certificate=K++,$.opReturn=K++,$.beacon=K++,y&&($.serviceFee=K++),{tld:u,category:Dt(A),transaction:F,sourceOutputs:I.map(St),inputUtxos:I,outputMap:$,payload:d,costs:{certificateDustSats:N,beaconDustSats:B,serviceFeeSats:p,chainFeeSats:_,changeSats:S,totalInputSats:b,netCostSats:p+_+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function Ut({name:t,ownerAddress:e,ownerTokenAddress:n,records:o={},certificateUtxo:s,utxos:r,beaconAddress:a=dt,feeRate:i=1,addressToLockingBytecode:l}){if(typeof l!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let c=H(t);if(!s?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");let h=Dt(ft(c));if(s.token.nft.commitment!==h)throw new Error(`certificate commitment mismatch: holds "${Ue(X(s.token.nft.commitment))}", asked to update "${c}"`);let u=Z("UPD",c,o),d=l(e),p=l(n??e),m=l(a),f=N+B,g=M(r,f+400n,{requireGenesis:!1}),y=0n,w=0n,x=!0;for(let _=0;_<6;_++){let S=[s,...g.inputs],k=s.satoshis+g.totalSats,O=(E,C)=>{let P=[];return E&&P.push({lockingBytecode:d,valueSatoshis:C}),P.push({lockingBytecode:p,valueSatoshis:N,token:{amount:0n,category:X(s.token.category),nft:{capability:"none",commitment:ft(c)}}}),P.push({lockingBytecode:et(u),valueSatoshis:0n}),P.push({lockingBytecode:m,valueSatoshis:B}),{version:2,locktime:0,inputs:S.map(gt),outputs:P}},I=ut(O(!0,1000000n));y=BigInt(Math.ceil(I*i));let b=f+y;if(k<b){let E=M(r,b+200n,{requireGenesis:!1});if(E.inputs.length>g.inputs.length){g=E;continue}throw new J(`not enough funds: need ${b} sat, have ${k} sat`,{needSats:b,haveSats:k})}w=k-b,x=w>=W,x||(y=k-f,w=0n);let R=O(x,w),A={},v=0;return x&&(A.change=v++),A.certificate=v++,A.opReturn=v++,A.beacon=v++,{name:c,displayName:Q(c),category:s.token.category,transaction:R,sourceOutputs:S.map(St),inputUtxos:S,outputMap:A,payload:u,costs:{certificateDustSats:N,beaconDustSats:B,serviceFeeSats:0n,chainFeeSats:y,changeSats:w,totalInputSats:k,netCostSats:y+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function $e({tld:t,ownerAddress:e,ownerTokenAddress:n,records:o={},certificateUtxo:s,utxos:r,beaconAddress:a=ne,feeRate:i=1,addressToLockingBytecode:l}){if(typeof l!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let c=Tt(t);if(!s?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");let h=Dt(ft(c));if(s.token.nft.commitment!==h)throw new Error(`TLD certificate commitment mismatch: holds "${Ue(X(s.token.nft.commitment))}", asked to update ".${c}"`);let u=Z("TUPD",c,o),d=l(e),p=l(n??e),m=l(a),f=N+B,g=M(r,f+400n,{requireGenesis:!1}),y=0n,w=0n,x=!0;for(let _=0;_<6;_++){let S=[s,...g.inputs],k=s.satoshis+g.totalSats,O=(E,C)=>{let P=[];return E&&P.push({lockingBytecode:d,valueSatoshis:C}),P.push({lockingBytecode:p,valueSatoshis:N,token:{amount:0n,category:X(s.token.category),nft:{capability:"none",commitment:ft(c)}}}),P.push({lockingBytecode:et(u),valueSatoshis:0n}),P.push({lockingBytecode:m,valueSatoshis:B}),{version:2,locktime:0,inputs:S.map(gt),outputs:P}},I=ut(O(!0,1000000n));y=BigInt(Math.ceil(I*i));let b=f+y;if(k<b){let E=M(r,b+200n,{requireGenesis:!1});if(E.inputs.length>g.inputs.length){g=E;continue}throw new J(`not enough funds: need ${b} sat, have ${k} sat`,{needSats:b,haveSats:k})}w=k-b,x=w>=W,x||(y=k-f,w=0n);let R=O(x,w),A={},v=0;return x&&(A.change=v++),A.certificate=v++,A.opReturn=v++,A.beacon=v++,{tld:c,displayName:`.${c}`,category:s.token.category,transaction:R,sourceOutputs:S.map(St),inputUtxos:S,outputMap:A,payload:u,costs:{certificateDustSats:N,beaconDustSats:B,serviceFeeSats:0n,chainFeeSats:y,changeSats:w,totalInputSats:k,netCostSats:y+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function Et({ownerAddress:t,utxos:e,amountSats:n=10000n,feeRate:o=1,addressToLockingBytecode:s}){let r=s(t),a=M(e,n+400n,{requireGenesis:!1});if(a.inputs.length===0)throw new J("wallet is empty");for(let i=0;i<6;i++){let{inputs:l,totalSats:c}=a,h=(m,f)=>({version:2,locktime:0,inputs:l.map(gt),outputs:[{lockingBytecode:r,valueSatoshis:n},...m?[{lockingBytecode:r,valueSatoshis:f}]:[]]}),u=BigInt(Math.ceil(ut(h(!0,1000000n))*o));if(c<n+u){let m=BigInt(Math.ceil(ut(h(!1,0n))*o));if(c<=m+W)throw new J(`not enough funds to prepare the wallet: have ${c} sat`,{needSats:m+W,haveSats:c});return{transaction:{version:2,locktime:0,inputs:l.map(gt),outputs:[{lockingBytecode:r,valueSatoshis:c-m}]},sourceOutputs:l.map(St),inputUtxos:l,costs:{chainFeeSats:m}}}let d=c-n-u,p=d>=W;return{transaction:h(p,d),sourceOutputs:l.map(St),inputUtxos:l,costs:{chainFeeSats:p?u:c-n}}}throw new Error("could not converge on a fee \u2014 please retry")}function mt(t){return t.some(e=>e.vout===0&&!e.token)}function Me({transaction:t,sourceOutputs:e},{broadcast:n=!0,userPrompt:o}={}){return{transaction:t,sourceOutputs:e,broadcast:n,...o?{userPrompt:o}:{}}}import{generateSigningSerializationBCH as Vn,hash256 as Ke,secp256k1 as Xn,encodeTransaction as Jn,binToHex as ie}from"@bitauth/libauth";var He=65;function ht(t,e,n){let o={...t,inputs:t.inputs.map((r,a)=>{let i=e[a],l=n(ie(i.lockingBytecode));if(!l)throw new Error(`no key for input ${a} \u2014 cannot sign`);let c=Vn({inputIndex:a,sourceOutputs:e,transaction:t},{coveredBytecode:i.lockingBytecode,signingSerializationType:Uint8Array.of(He)}),h=Ke(c),u=Xn.signMessageHashSchnorr(l.privateKey,h);if(typeof u=="string")throw new Error(`signing failed on input ${a}: ${u}`);let d=Uint8Array.from([...u,He]);return{...r,unlockingBytecode:Uint8Array.from([d.length,...d,l.publicKey.length,...l.publicKey])}})},s=Jn(o);return{transaction:o,hex:ie(s),txid:ae(s)}}function ae(t){return ie(Ke(t).slice().reverse())}function ce(t){let e=new Uint8Array(t.length/2);for(let n=0;n<e.length;n++)e[n]=parseInt(t.substr(n*2,2),16);return ae(e)}var D={network:T.id,addressPrefix:T.prefix,explorerTx:T.explorerTx,selfHosted:null,get electrum(){return this.selfHosted?[this.selfHosted,...Rt]:Rt},beacon:T.beacon,tldBeacon:T.tldBeacon,serviceFee:{address:T.operatorAddress,sats:10000n},feeRate:1,wizardConnect:{dappName:"Silent Mode",dappIcon:"https://silentmode.st/icon.png"},faucets:T.faucets};function Qn(t){let e=r=>(Number(r)/1e8).toFixed(8).replace(/0+$/,"").replace(/\.$/,""),n=[],o=BigInt(t.tldOwnerFeeSats??0n),s=BigInt(t.serviceFeeSats??0n);return o>0n?(n.push({label:"Service fee \u2014 TLD owner (90%)",sats:o,bch:e(o),note:"goes to whoever holds this TLD's certificate on chain"}),n.push({label:"Service fee \u2014 platform (10%)",sats:s,bch:e(s),note:"covers the resolver + gateway + indexer"})):n.push({label:"Service fee",sats:s,bch:e(s)}),n.push({label:"Network fee",sats:t.chainFeeSats,bch:e(t.chainFeeSats)}),n.push({label:"Discovery beacon",sats:t.beaconDustSats,bch:e(t.beaconDustSats)}),n.push({label:"Held in the certificate",sats:t.certificateDustSats,bch:e(t.certificateDustSats),note:"stays yours \u2014 it lives in the certificate you now own"}),n.push({label:"Total",sats:t.netCostSats,bch:e(t.netCostSats),total:!0}),n}import{hexToBin as Ve,binToHex as yt,decodeTransaction as so,lockingBytecodeToCashAddress as ro,sha256 as io,utf8ToBin as ao,binToBase64 as co}from"@bitauth/libauth";import{encodeTransaction as ue,decodeTransaction as We,generateSigningSerializationBCH as Ge,hash256 as de,hash160 as Zn,secp256k1 as ze,hexToBin as rt,binToHex as U,utf8ToBin as qe}from"@bitauth/libauth";var Ft=65,le=195,nt=(t,e)=>({outpointTransactionHash:rt(t.txid),outpointIndex:t.vout,sequenceNumber:4294967294,unlockingBytecode:e??se()}),it=t=>t?{amount:BigInt(t.amount??0),category:rt(t.category),...t.nft?{nft:{capability:t.nft.capability,commitment:rt(t.nft.commitment||"")}}:{}}:void 0,he=t=>({lockingBytecode:t.lockingBytecode instanceof Uint8Array?U(t.lockingBytecode):String(t.lockingBytecode),valueSatoshis:String(t.valueSatoshis),...t.token?{token:{category:t.token.category instanceof Uint8Array?U(t.token.category):String(t.token.category),amount:String(t.token.amount??0),...t.token.nft?{nft:{capability:t.token.nft.capability,commitment:t.token.nft.commitment instanceof Uint8Array?U(t.token.nft.commitment):String(t.token.nft.commitment||"")}}:{}}}:{}}),pe=t=>({lockingBytecode:rt(t.lockingBytecode),valueSatoshis:BigInt(t.valueSatoshis??t.satoshis),...t.token?{token:it(t.token)}:{}}),at=(t,e)=>({...nt(t,e),lockingBytecode:t.lockingBytecode instanceof Uint8Array?t.lockingBytecode:rt(t.lockingBytecode),valueSatoshis:BigInt(t.satoshis),...t.token?{token:it(t.token)}:{}});function je(t,e,n,o,s){let r=e[n],a=Ge({inputIndex:n,sourceOutputs:e,transaction:t},{coveredBytecode:r.lockingBytecode,signingSerializationType:Uint8Array.of(s)}),i=de(a),l=ze.signMessageHashSchnorr(o.privateKey,i);if(typeof l=="string")throw new Error(`signing failed on input ${n}: ${l}`);let c=Uint8Array.from([...l,s]);return Uint8Array.from([c.length,...c,o.publicKey.length,...o.publicKey])}function _t(t,e,n,{sighash:o=Ft,skip:s=[]}={}){let r={...t,inputs:t.inputs.map((i,l)=>{if(s.includes(l))return i;let c=n(U(e[l].lockingBytecode));return c?{...i,unlockingBytecode:je(t,e,l,c,o)}:i})},a=ue(r);return{transaction:r,hex:U(a),txid:U(de(a).slice().reverse())}}function to({name:t,certificateUtxo:e,priceSats:n,sellerAddress:o,addressToLockingBytecode:s,keyFor:r}){let a=H(t),i=BigInt(n);if(i<W)throw new Error(`price must be at least ${W} sat`);if(!e?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");if(e.token.nft.commitment!==U(qe(a)))throw new Error("certificate commitment does not match the name");let l=s(o),c=at(e),h={version:2,locktime:0,inputs:[nt(e)],outputs:[{lockingBytecode:l,valueSatoshis:i}]},u=r(U(c.lockingBytecode));if(!u)throw new Error("this wallet does not hold the key for the certificate");return h.inputs[0].unlockingBytecode=je(h,[c],0,u,le),{v:1,name:a,seller:o,price_sats:i.toString(),category:e.token.category,partial_tx:U(ue(h)),source_output:{txid:e.txid,vout:e.vout,satoshis:BigInt(e.satoshis).toString(),lockingBytecode:U(c.lockingBytecode),token:{category:e.token.category,amount:String(e.token.amount??0),nft:e.token.nft?{capability:e.token.nft.capability,commitment:e.token.nft.commitment}:void 0}},created_at:new Date().toISOString()}}function eo(t){let e=t[0],n=t.slice(1,1+e),o=t[1+e],s=t.slice(2+e,2+e+o);return{sig:n,pubkey:s}}var no=t=>Uint8Array.from([118,169,20,...Zn(t),136,172]);function Ye(t,e={}){let n=o=>({ok:!1,error:o});try{if(!t||t.v!==1)return n("unsupported listing version");let o=H(t.name),s=We(rt(t.partial_tx));if(typeof s=="string")return n("partial_tx does not decode: "+s);if(s.inputs.length!==1||s.outputs.length<1)return n("partial_tx must have exactly one input and a payment output");let r=t.source_output;if(!r?.token?.nft)return n("source_output carries no certificate");if(U(s.inputs[0].outpointTransactionHash)!==r.txid||s.inputs[0].outpointIndex!==r.vout)return n("input does not spend source_output");if(r.token.nft.commitment!==U(qe(o)))return n("certificate commitment does not match the name");if(e.category&&r.token.category!==e.category)return n("certificate category does not match the registry");let a=s.outputs[0].valueSatoshis;if(a<W)return n("price below dust");if(BigInt(t.price_sats)!==a)return n("price_sats does not match output 0");let{sig:i,pubkey:l}=eo(s.inputs[0].unlockingBytecode);if(i.length!==65||i[64]!==le)return n("input 0 is not signed SINGLE|ANYONECANPAY");let c=rt(r.lockingBytecode);if(U(no(l))!==U(c))return n("public key does not own the certificate output");if(e.ownerLockingBytecode&&U(c)!==e.ownerLockingBytecode)return n("certificate is not held by the current owner");if(U(s.outputs[0].lockingBytecode)!==U(c))return n("payment does not go to the certificate holder");let h={...s.inputs[0],lockingBytecode:c,valueSatoshis:BigInt(r.satoshis),token:it(r.token)},u=Ge({inputIndex:0,sourceOutputs:[h],transaction:s},{coveredBytecode:c,signingSerializationType:Uint8Array.of(le)});return ze.verifySignatureSchnorr(i.slice(0,64),l,de(u))?{ok:!0,name:o,price_sats:a,seller_lock:U(c),category:r.token.category}:n("seller signature is invalid")}catch(o){return n(String(o?.message||o))}}function oo({listing:t,buyerAddress:e,buyerTokenAddress:n,utxos:o,records:s={},beaconAddress:r=dt,feeRate:a=1,addressToLockingBytecode:i}){let l=Ye(t);if(!l.ok)throw new Error("bad listing: "+l.error);let c=l.name,h=We(rt(t.partial_tx)),u=t.source_output,d=h.inputs[0],p={...d,lockingBytecode:rt(u.lockingBytecode),valueSatoshis:BigInt(u.satoshis),token:it(u.token)},m=h.outputs[0],f=m.valueSatoshis,g=i(e),y=i(n??e),w=i(r),x=Z("UPD",c,s),_=f+N+B-BigInt(u.satoshis),S=M(o,_+400n,{requireGenesis:!1}),k=O=>ue(O).length;for(let O=0;O<6;O++){let{inputs:I,totalSats:b}=S,R=(F,$)=>({version:2,locktime:0,inputs:[d,...I.map(K=>nt(K))],outputs:[m,{lockingBytecode:y,valueSatoshis:N,token:it(u.token)},{lockingBytecode:et(x),valueSatoshis:0n},{lockingBytecode:w,valueSatoshis:B},...F?[{lockingBytecode:g,valueSatoshis:$}]:[]]}),A=BigInt(Math.ceil(k(R(!0,1000000n))*a)),v=_+A;if(b<v){let F=M(o,v+200n,{requireGenesis:!1});if(F.inputs.length>I.length){S=F;continue}let $=new Error(`not enough funds: need ${v} sat, have ${b} sat`);throw $.needSats=v,$.haveSats=b,$}let E=b-v,C=E>=W;C||(E=0n);let P=R(C,E);return{name:c,transaction:P,sourceOutputs:[p,...I.map(F=>at(F))],sellerInputIndex:0,costs:{priceSats:f,beaconDustSats:B,certificateDustSats:N,chainFeeSats:C?A:b-_,changeSats:E,totalInputSats:b}}}throw new Error("could not converge on a fee \u2014 please retry")}var lo=90n,uo=100n;async function Xe(t,e,n=D.addressPrefix){let s=(await jt(t)).get(String(e).toLowerCase());if(!s?.mintScriptHex)return null;try{let r=Ve(s.mintScriptHex),a=ro({bytecode:r,prefix:n,tokenSupport:!1});return typeof a=="string"?null:a.address}catch{return null}}function Je(t){let e=BigInt(t??0n),n=e*lo/uo,o=e-n;return{tldOwnerFeeSats:n,platformFeeSats:o}}var ho=T.beaconOnly;async function po({electrum:t=D.electrum,WebSocket:e,beaconOk:n=!1}={}){let o=n?t:t.filter(s=>!ho.test(typeof s=="string"?s:s.url||""));return Le(o,e)}async function $t(t,e){let n=H(e),o=Q(n),r=(await bt({client:t})).get(o)??null;return{name:o,rawName:n,available:!r,entry:r,recordBudgetBytes:oe(n)}}async function Mt(t,{name:e,ownerAddress:n,records:o={},utxos:s,serviceFee:r=D.serviceFee,feeRate:a=D.feeRate,cosignUtxo:i=null,cosignTokenAddress:l=null}){let c=s??await j(t,[n]),h=H(e),u=h.indexOf("."),d=u<0?"bch":h.slice(u+1),p=BigInt(r.sats??0n),m=null,f=0n,g=p;if(p>0n){try{m=await Xe(t,d)}catch{m=null}if(m&&m!==n){let y=Je(p);f=y.tldOwnerFeeSats,g=y.platformFeeSats}}return re({name:e,ownerAddress:n,ownerTokenAddress:z(n),records:o,utxos:c,feeAddress:g>0n?r.address:null,feeSats:g,tldFeeAddress:f>0n?m:null,tldFeeSats:f,beaconAddress:D.beacon,feeRate:a,addressToLockingBytecode:L,cosignUtxo:i,cosignTokenAddress:l})}function Qe(t,{tld:e,category:n}){let o=[...new TextEncoder().encode(String(e).toLowerCase())].map(s=>s.toString(16).padStart(2,"0")).join("");return t.find(s=>s.token?.nft&&(!n||s.token.category===n)&&s.token.nft.commitment===o)??null}async function Ze(t,{wallet:e,utxos:n,feeRate:o,onProgress:s}){if(mt(n))return{utxos:n,prepTxid:null};s("preparing-wallet");let r=Et({ownerAddress:e.address,utxos:n,feeRate:o,addressToLockingBytecode:L}),a=ht(r.transaction,r.sourceOutputs,c=>e.keyFor(c)),i=await st(t,a.hex);return s("prepared",{txid:i}),{utxos:a.transaction.outputs.slice(0,2).map((c,h)=>({txid:i,vout:h,satoshis:c.valueSatoshis,address:e.address,lockingBytecode:L(e.address)})),prepTxid:i}}async function fo(t,{wallet:e,name:n,records:o={},serviceFee:s=D.serviceFee,feeRate:r=D.feeRate,tldCert:a,onProgress:i=()=>{}}){if(!a?.utxo?.token?.nft||!a.owner)throw new Error("tldCert must be the /api/tld-cert response ({ owner, utxo })");i("checking-availability");let l=await $t(t,n);if(!l.available)throw new Error(`"${l.name}" is already registered`);i("loading-coins");let c=await j(t,e.watchedAddresses);if(c.filter(g=>!g.token).reduce((g,y)=>g+y.satoshis,0n)===0n)throw new Error("wallet is empty \u2014 fund the address first");let u=null;({utxos:c,prepTxid:u}=await Ze(t,{wallet:e,utxos:c,feeRate:r,onProgress:i})),i("building");let d=await Mt(t,{name:n,ownerAddress:e.address,records:o,utxos:c,serviceFee:s,feeRate:r,cosignUtxo:{...a.utxo,address:a.owner},cosignTokenAddress:z(a.owner)}),p=d.transaction.inputs.length-1;i("signing");let m={...d.transaction,inputs:d.transaction.inputs.map((g,y)=>y===p?{...g,unlockingBytecode:new Uint8Array}:g)},f=_t(m,d.sourceOutputs,g=>e.keyFor(g),{skip:[p]});return{name:d.name,displayName:d.displayName,category:d.category,tx:f.hex,sourceOutputs:d.sourceOutputs.map(he),cosignInputIndex:p,costs:d.costs,prepTxid:u}}function go(t,e){let n=so(Ve(String(t.tx||"")));if(typeof n=="string")throw new Error("invalid transaction: "+n);let o=(t.sourceOutputs||[]).map(pe);if(o.length!==n.inputs.length)throw new Error("sourceOutputs do not match the transaction inputs");let s=[],r=0;n.inputs.forEach((i,l)=>{let c=o[l];if(!e(yt(c.lockingBytecode))){s.push(l);return}if(c.token?.nft&&!n.outputs.some(u=>u.token&&yt(u.token.category)===yt(c.token.category)&&yt(u.token.nft?.commitment??new Uint8Array)===yt(c.token.nft.commitment??new Uint8Array)&&yt(u.lockingBytecode)===yt(c.lockingBytecode)&&u.valueSatoshis>=c.valueSatoshis))throw new Error("refusing to sign: the request would not return your TLD certificate to you");r+=1});let a=_t(n,o,e,{skip:s});return{hex:a.hex,txid:a.txid,signedInputs:r}}async function mo(t,{wallet:e,name:n,records:o={},serviceFee:s=D.serviceFee,feeRate:r=D.feeRate,cosign:a=null,onProgress:i=()=>{}}){i("checking-availability");let l=await $t(t,n);if(!l.available)throw new Error(`"${l.name}" is already registered`);i("loading-coins");let c=await j(t,e.watchedAddresses);if(c.filter(g=>!g.token).reduce((g,y)=>g+y.satoshis,0n)===0n)throw new Error("wallet is empty \u2014 fund the address first");let u=null;if(a&&(u=Qe(c,a),!u))throw new Error(`this wallet does not hold the certificate for .${a.tld} \u2014 only the TLD owner can co-sign`);let d=null;({utxos:c,prepTxid:d}=await Ze(t,{wallet:e,utxos:c,feeRate:r,onProgress:i})),i("building");let p=await Mt(t,{name:n,ownerAddress:e.address,records:o,utxos:c,serviceFee:s,feeRate:r,cosignUtxo:u,cosignTokenAddress:u?z(e.address):null});i("signing");let m=ht(p.transaction,p.sourceOutputs,g=>e.keyFor(g));i("broadcasting");let f=await st(t,m.hex);return i("registered",{txid:f,category:p.category}),{name:p.name,displayName:p.displayName,category:p.category,txid:f,prepTxid:d,ownerAddress:e.address,certificateAddress:z(e.address),costs:p.costs,hex:m.hex}}async function yo(t,{wallet:e,tld:n,records:o={},serviceFee:s={address:null,sats:0n},feeRate:r=D.feeRate,tldListUrl:a=null,onProgress:i=()=>{}}){let l=Tt(n);if(i("checking-availability"),a)try{let f=await fetch(a);if(f.ok){let g=await f.json();if(Array.isArray(g.tlds)&&g.tlds.some(w=>(w.tld||w)===l))throw new Error(`".${l}" is already registered as a TLD`)}}catch(f){if(/already registered/.test(f.message))throw f}i("loading-coins");let c=await j(t,e.watchedAddresses);if(c.filter(f=>!f.token).reduce((f,g)=>f+g.satoshis,0n)===0n)throw new Error("wallet is empty \u2014 fund the address first");let u=null;if(!mt(c)){i("preparing-wallet");let f=Et({ownerAddress:e.address,utxos:c,feeRate:r,addressToLockingBytecode:L}),g=ht(f.transaction,f.sourceOutputs,y=>e.keyFor(y));u=await st(t,g.hex),i("prepared",{txid:u}),c=[{txid:u,vout:0,satoshis:g.transaction.outputs[0].valueSatoshis,address:e.address,lockingBytecode:L(e.address)},...g.transaction.outputs.length>1?[{txid:u,vout:1,satoshis:g.transaction.outputs[1].valueSatoshis,address:e.address,lockingBytecode:L(e.address)}]:[]]}i("building");let d=Ct({tld:l,ownerAddress:e.address,ownerTokenAddress:z(e.address),changeAddress:e.address,records:o,utxos:c,feeAddress:s.address||null,feeSats:BigInt(s.sats??0n),feeRate:r,addressToLockingBytecode:L});i("signing");let p=ht(d.transaction,d.sourceOutputs,f=>e.keyFor(f));i("broadcasting");let m=await st(t,p.hex);return i("registered",{txid:m,category:d.category}),{tld:d.tld,category:d.category,txid:m,prepTxid:u,ownerAddress:e.address,certificateAddress:z(e.address),costs:d.costs,hex:p.hex}}async function wo(t,{session:e,tld:n,records:o={},serviceFee:s={address:null,sats:0n},feeRate:r=D.feeRate,tldListUrl:a=null,onProgress:i=()=>{}}){let l=Tt(n);if(i("checking-availability"),a)try{let g=await fetch(a);if(g.ok){let y=await g.json();if(Array.isArray(y.tlds)&&y.tlds.some(x=>(x.tld||x)===l))throw new Error(`".${l}" is already registered as a TLD`)}}catch(g){if(/already registered/.test(g.message))throw g}i("reading-wallet");let c=await e.getAddresses();if(!c.length)throw new Error("the wallet exposed no addresses");let h=c[0];i("loading-coins");let u=await j(t,c);if(u.filter(g=>!g.token).reduce((g,y)=>g+y.satoshis,0n)===0n)throw new Error("the connected wallet has no spendable coins");let d=null;if(!mt(u)){i("preparing-wallet");let g=Et({ownerAddress:h,utxos:u,feeRate:r,addressToLockingBytecode:L}),y=await e.signTransaction(g,{userPrompt:"One-time setup so your wallet can create a TLD certificate"});d=await Bt(t,e,y,i),i("prepared",{txid:d}),u=[{txid:d,vout:0,satoshis:g.transaction.outputs[0].valueSatoshis,address:h,lockingBytecode:L(h)},...u.filter(w=>!w.token&&!g.inputUtxos.some(x=>x.txid===w.txid&&x.vout===w.vout))]}i("building");let p=Ct({tld:l,ownerAddress:h,ownerTokenAddress:z(h),changeAddress:h,records:o,utxos:u,feeAddress:s.address||null,feeSats:BigInt(s.sats??0n),feeRate:r,addressToLockingBytecode:L});i("awaiting-approval");let m=await e.signTransaction(p,{userPrompt:`Register .${l} \u2014 the TLD certificate is minted to your own address`}),f=await Bt(t,e,m,i);return i("registered",{txid:f,category:p.category}),{tld:p.tld,category:p.category,txid:f,prepTxid:d,ownerAddress:h,certificateAddress:z(h),costs:p.costs}}async function Bt(t,e,n,o){let s=n.signedTransactionHash??ce(n.signedTransaction);if(e.walletBroadcasts)return s;o("broadcasting");try{return await st(t,n.signedTransaction)}catch(r){let a=String(r?.message??r);if(/already|duplicate|txn-already|in mempool/i.test(a))return s;throw r}}async function xo(t,{session:e,name:n,ownerAddress:o,records:s={},serviceFee:r=D.serviceFee,feeRate:a=D.feeRate,onProgress:i=()=>{}}){i("checking-availability");let l=await $t(t,n);if(!l.available)throw new Error(`"${l.name}" is already registered`);i("reading-wallet");let c=await e.getAddresses();if(!c.length)throw new Error("the wallet exposed no addresses");let h=o??c[0];i("loading-coins");let u=await j(t,c);if(!u.some(f=>!f.token))throw new Error("the connected wallet has no spendable coins");if(!mt(u)){i("preparing-wallet");let f=Et({ownerAddress:h,utxos:u,feeRate:a,addressToLockingBytecode:L}),g=await e.signTransaction(f,{userPrompt:"One-time setup so your wallet can create a name certificate"}),y=await Bt(t,e,g,i);i("prepared",{txid:y}),u=[{txid:y,vout:0,satoshis:f.transaction.outputs[0].valueSatoshis,address:h,lockingBytecode:L(h)},...u.filter(w=>!w.token&&!f.inputUtxos.some(x=>x.txid===w.txid&&x.vout===w.vout))]}i("building");let d=await Mt(t,{name:n,ownerAddress:h,records:s,utxos:u,serviceFee:r,feeRate:a});i("awaiting-approval");let p=await e.signTransaction(d,{userPrompt:`Register ${d.displayName} \u2014 the certificate is minted to your own address`}),m=await Bt(t,e,p,i);return i("registered",{txid:m,category:d.category}),{name:d.name,displayName:d.displayName,category:d.category,txid:m,ownerAddress:h,certificateAddress:z(h),costs:d.costs}}async function ko(t,{addresses:e,category:n,rawName:o}){let s=await j(t,e),r=[...new TextEncoder().encode(o)].map(a=>a.toString(16).padStart(2,"0")).join("");return s.find(a=>a.token?.category===n&&a.token?.nft?.commitment===r)??null}async function bo(t,{wallet:e,name:n,records:o,feeRate:s=D.feeRate,onProgress:r=()=>{}}){r("resolving");let a=H(n),l=(await bt({client:t})).get(Q(a));if(!l)throw new Error(`"${Q(a)}" is not registered`);r("loading-coins");let c=await j(t,e.watchedAddresses),h=c.find(m=>m.token?.category===l.category&&m.token?.nft);if(!h)throw new Error(`this wallet does not hold the certificate for "${Q(a)}" \u2014 only the owner can change its records`);r("building");let u=Ut({name:n,ownerAddress:e.address,ownerTokenAddress:z(e.address),records:o,certificateUtxo:h,utxos:c.filter(m=>!m.token),beaconAddress:D.beacon,feeRate:s,addressToLockingBytecode:L});r("signing");let d=ht(u.transaction,u.sourceOutputs,m=>e.keyFor(m));r("broadcasting");let p=await st(t,d.hex);return r("updated",{txid:p}),{name:u.name,displayName:u.displayName,category:u.category,txid:p,records:o,costs:u.costs}}async function So(t,{session:e,name:n,records:o,feeRate:s=D.feeRate,onProgress:r=()=>{}}){r("resolving");let a=H(n),l=(await bt({client:t})).get(Q(a));if(!l)throw new Error(`"${Q(a)}" is not registered`);r("reading-wallet");let c=await e.getAddresses(),h=await j(t,c),u=h.find(f=>f.token?.category===l.category&&f.token?.nft);if(!u)throw new Error(`this wallet does not hold the certificate for "${Q(a)}" \u2014 only the owner can change its records`);r("building");let d=Ut({name:n,ownerAddress:u.address,ownerTokenAddress:z(u.address),records:o,certificateUtxo:u,utxos:h.filter(f=>!f.token),beaconAddress:D.beacon,feeRate:s,addressToLockingBytecode:L});r("awaiting-approval");let p=await e.signTransaction(d,{userPrompt:`Point ${d.displayName} somewhere new`}),m=await Bt(t,e,p,r);return r("updated",{txid:m}),{name:d.name,displayName:d.displayName,category:d.category,txid:m,records:o,costs:d.costs}}async function To(t,{wallet:e,tld:n,records:o,category:s,feeRate:r=D.feeRate,onProgress:a=()=>{}}){if(!s)throw new Error("setTldRecords requires the TLD certificate's category id");a("loading-coins");let i=await j(t,e.watchedAddresses),l=i.find(d=>d.token?.category===s&&d.token?.nft);if(!l)throw new Error(`this wallet does not hold the TLD certificate for ".${n}" \u2014 only the owner can change its policy`);a("building");let c=$e({tld:n,ownerAddress:e.address,ownerTokenAddress:z(e.address),records:o,certificateUtxo:l,utxos:i.filter(d=>!d.token),feeRate:r,addressToLockingBytecode:L});a("signing");let h=ht(c.transaction,c.sourceOutputs,d=>e.keyFor(d));a("broadcasting");let u=await st(t,h.hex);return a("updated",{txid:u}),{tld:c.tld,displayName:c.displayName,category:c.category,txid:u,records:o,costs:c.costs}}async function Eo(t,e){if(!e||e.v!==1)throw new Error("manifest.v must be 1");if(!e.name)throw new Error("manifest.name is required");if(typeof e.seq!="number"||e.seq<0)throw new Error("manifest.seq must be a non-negative integer");let n={...e};delete n.sig;let o=JSON.stringify(fe(n)),s=io.hash(ao(o)),r=t.signMessage(s);return{...e,sig:co(r)}}function fe(t){if(t!=null){if(Array.isArray(t))return t.map(fe).filter(e=>e!==void 0);if(typeof t=="object"){let e={};for(let n of Object.keys(t).sort()){let o=fe(t[n]);o!==void 0&&(e[n]=o)}return e}return t}}async function _o(t,e){let n=await j(t,e),o=n.filter(s=>!s.token);return{sats:o.reduce((s,r)=>s+r.satoshis,0n),confirmedSats:o.filter(s=>s.height>0).reduce((s,r)=>s+r.satoshis,0n),coins:o.length,certificates:n.filter(s=>s.token?.nft),hasGenesisInput:mt(n)}}import{hexToBin as Y,binToHex as tt,encodeDataPush as G,bigIntToVmNumber as Kt,hash256 as ge,hash160 as Oo,encodeLockingBytecodeP2sh32 as vo,encodeLockingBytecodeP2pkh as on,lockingBytecodeToCashAddress as Ao,OpcodesBCH as Bo,numberToBinUint32LE as Ms,binToNumberUint32LE as en,secp256k1 as sn,sha256 as Io,generateSigningSerializationBCH as Po,encodeTransaction as rn,flattenBinArray as Ot}from"@bitauth/libauth";var tn={contractName:"UsdListing",constructorInputs:[{name:"oraclePk",type:"pubkey"},{name:"sellerPkh",type:"bytes20"},{name:"targetCents",type:"int"},{name:"floorSats",type:"int"},{name:"ceilSats",type:"int"},{name:"maxAgeSecs",type:"int"}],abi:[{name:"buy",inputs:[{name:"oracleMsg",type:"bytes"},{name:"oracleSig",type:"datasig"}]},{name:"cancel",inputs:[{name:"pk",type:"pubkey"},{name:"s",type:"sig"}]}],bytecode:"OP_6 OP_PICK OP_0 OP_NUMEQUAL OP_IF OP_TXLOCKTIME OP_CHECKLOCKTIMEVERIFY OP_DROP OP_7 OP_PICK OP_SIZE OP_NIP 28 OP_NUMEQUALVERIFY OP_8 OP_ROLL OP_8 OP_PICK OP_ROT OP_CHECKDATASIGVERIFY OP_6 OP_ROLL OP_4 OP_SPLIT OP_4 OP_SPLIT OP_ROT OP_BIN2NUM OP_ROT OP_BIN2NUM OP_DUP OP_0 OP_GREATERTHAN OP_VERIFY OP_ROT OP_INPUTINDEX OP_OUTPOINTTXHASH OP_EQUALVERIFY OP_TXLOCKTIME 302a OP_ADD OP_2 OP_PICK OP_GREATERTHANOREQUAL OP_VERIFY OP_TXLOCKTIME OP_ROT OP_7 OP_ROLL OP_ADD OP_LESSTHANOREQUAL OP_VERIFY OP_ROT 00e1f505 OP_MUL OP_SWAP OP_DIV OP_DUP OP_3 OP_PICK OP_LESSTHAN OP_IF OP_2 OP_PICK OP_NIP OP_ENDIF OP_DUP OP_4 OP_PICK OP_GREATERTHAN OP_IF OP_3 OP_PICK OP_NIP OP_ENDIF OP_0 OP_OUTPUTBYTECODE 76a914 OP_3 OP_ROLL OP_CAT 88ac OP_CAT OP_EQUALVERIFY OP_0 OP_OUTPUTVALUE OP_LESSTHANOREQUAL OP_VERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENCATEGORY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENCOMMITMENT OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_EQUAL OP_NIP OP_NIP OP_NIP OP_ELSE OP_6 OP_ROLL OP_1 OP_NUMEQUALVERIFY OP_6 OP_PICK OP_HASH160 OP_ROT OP_EQUALVERIFY OP_6 OP_ROLL OP_6 OP_ROLL OP_CHECKSIGVERIFY OP_2DROP OP_2DROP OP_DROP OP_1 OP_ENDIF",compiler:{name:"cashc",version:"0.13.3",options:{enforceFunctionParameterTypes:!0,enforceLocktimeGuard:!0}}};var No=2,me=1200,Ro=7200,Lo=t=>{let e=Bo[t];if(e===void 0)throw new Error("unknown opcode "+t);return Uint8Array.of(e)};function Do(t){let e=t.trim().split(/\s+/).filter(Boolean).map(n=>n.startsWith("OP_")?Lo(n):G(Y(n)));return Ot(e)}var Co=Do(tn.bytecode),Ht=t=>G(Kt(BigInt(t))),Uo=0,nn=1;function Fo(t){let e=Y(t);if(e.length!==25||e[0]!==118||e[1]!==169||e[2]!==20)throw new Error("seller must hold the certificate on a plain P2PKH address");return tt(e.slice(3,23))}function ye({oraclePk:t,sellerPkh:e,targetCents:n,floorSats:o,ceilSats:s,maxAgeSecs:r=me}){if(!(BigInt(n)>0n)||!(BigInt(o)>0n)||BigInt(s)<BigInt(o))throw new Error("bad listing terms");return Ot([Ht(r),Ht(s),Ht(o),Ht(n),G(Y(e)),G(Y(t)),Co])}var Wt=t=>vo(ge(t));function we(t,e=T.prefix){let n=Ao({bytecode:Wt(t),prefix:e});if(typeof n=="string")throw new Error(n);return n.address}function an({targetCents:t,priceCents:e,floorSats:n,ceilSats:o}){let s=BigInt(t)*100000000n/BigInt(e);return s<BigInt(n)&&(s=BigInt(n)),s>BigInt(o)&&(s=BigInt(o)),s}var cn=t=>({ts:en(t.slice(0,4)),priceCents:en(t.slice(4,8)),outpointTxid:tt(t.slice(8,40).slice().reverse())});function ln(t,e,n){return sn.verifySignatureSchnorr(n,t,Io.hash(e))===!0}var xe=(t,e,n,o,{requireGenesis:s=!1}={})=>{let r=M(t,e+600n,{requireGenesis:s});for(let a=0;a<6;a++){let{inputs:i,totalSats:l}=r,c=o(i,!0,1000000n),h=BigInt(Math.ceil(rn(c.transaction).length*n)),u=e+h;if(l<u){let m=M(t,u+200n,{requireGenesis:s});if(m.inputs.length>i.length){r=m;continue}let f=new Error(`not enough funds: need ${u} sat, have ${l} sat`);throw f.needSats=u,f.haveSats=l,f}let d=l-u,p=d>=W;return p||(d=0n),{...o(i,p,d),fee:p?h:l-e,change:d}}throw new Error("could not converge on a fee \u2014 please retry")};function $o({name:t,certificateUtxo:e,utxos:n,sellerAddress:o,oraclePk:s,targetCents:r,floorSats:a,ceilSats:i,maxAgeSecs:l=me,records:c={},beaconAddress:h=dt,feeRate:u=1,addressToLockingBytecode:d}){let p=H(t);if(!e?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");let m=d(o),f=Fo(tt(d(e.address||o))),g=ye({oraclePk:s,sellerPkh:f,targetCents:r,floorSats:a,ceilSats:i,maxAgeSecs:l}),y=Wt(g),w=Z("UPD",p,c),x=n.filter(k=>!k.token),_=N+B-BigInt(e.satoshis);return{...xe(x,_>0n?_:0n,u,(k,O,I)=>({transaction:{version:2,locktime:0,inputs:[nt(e),...k.map(b=>nt(b))],outputs:[{lockingBytecode:y,valueSatoshis:N,token:it(e.token)},{lockingBytecode:et(w),valueSatoshis:0n},{lockingBytecode:d(h),valueSatoshis:B},...O?[{lockingBytecode:m,valueSatoshis:I}]:[]]},sourceOutputs:[at(e),...k.map(b=>at(b))]})),name:p,redeem:g,redeemHex:tt(g),address:we(g,o.split(":")[0]),sellerPkh:f,covenantVout:0}}function un(t){let e=Y(t.redeem_hex);return{redeem:e,utxo:{txid:t.outpoint.txid,vout:t.outpoint.vout,satoshis:BigInt(t.outpoint.satoshis??N),lockingBytecode:Wt(e),token:t.token}}}function Mo({listing:t,quote:e,buyerAddress:n,buyerTokenAddress:o,utxos:s,records:r={},beaconAddress:a=dt,feeRate:i=1,addressToLockingBytecode:l}){let c=H(t.name),h=Y(e.message),u=Y(e.signature);if(!ln(Y(t.oracle_pk),h,u))throw new Error("oracle signature does not verify against the listing's oracle key");let{ts:d,priceCents:p,outpointTxid:m}=cn(h);if(m!==String(t.outpoint.txid).toLowerCase())throw new Error("quote was issued for a different listing");let f=an({targetCents:t.target_cents,priceCents:p,floorSats:t.floor_sats,ceilSats:t.ceil_sats}),{redeem:g,utxo:y}=un(t),w=on(Y(t.seller_pkh)),x=Ot([G(u),G(h),G(Kt(BigInt(Uo))),G(g)]),_=l(n),S=l(o??n),k=Z("UPD",c,r),O=s.filter(R=>!R.token),I=f+N+B-y.satoshis;return{...xe(O,I,i,(R,A,v)=>({transaction:{version:2,locktime:Math.max(0,d-Ro),inputs:[nt(y,x),...R.map(E=>nt(E))],outputs:[{lockingBytecode:w,valueSatoshis:f},{lockingBytecode:S,valueSatoshis:N,token:it(y.token)},{lockingBytecode:et(k),valueSatoshis:0n},{lockingBytecode:l(a),valueSatoshis:B},...A?[{lockingBytecode:_,valueSatoshis:v}]:[]]},sourceOutputs:[at(y),...R.map(E=>at(E))]})),name:c,covenantInputIndex:0,priceSats:f,priceCents:p,quoteTs:d}}function Ho({listing:t,sellerAddress:e,sellerTokenAddress:n,utxos:o,records:s={},beaconAddress:r=dt,feeRate:a=1,addressToLockingBytecode:i,keyFor:l}){let c=H(t.name),{redeem:h,utxo:u}=un(t),d=on(Y(t.seller_pkh)),p=l(tt(d));if(!p)throw new Error("this wallet does not hold the seller key for this listing");let m=p.privateKey,f=p.publicKey,g=i(n??e),y=Z("UPD",c,s),w=o.filter(E=>!E.token),x=N+B-u.satoshis,_=Ot([G(new Uint8Array(65)),G(f),G(Kt(BigInt(nn))),G(h)]),S=xe(w,x>0n?x:0n,a,(E,C,P)=>({transaction:{version:2,locktime:0,inputs:[nt(u,_),...E.map(F=>nt(F))],outputs:[{lockingBytecode:g,valueSatoshis:N,token:it(u.token)},{lockingBytecode:et(y),valueSatoshis:0n},{lockingBytecode:i(r),valueSatoshis:B},...C?[{lockingBytecode:i(e),valueSatoshis:P}]:[]]},sourceOutputs:[at(u),...E.map(F=>at(F))]})),k=_t(S.transaction,S.sourceOutputs,l,{skip:[0]}),O=Po({inputIndex:0,sourceOutputs:S.sourceOutputs,transaction:k.transaction},{coveredBytecode:h,signingSerializationType:Uint8Array.of(Ft)}),I=sn.signMessageHashSchnorr(m,ge(O));if(typeof I=="string")throw new Error(I);let b=Ot([I,Uint8Array.of(Ft)]),R=Ot([G(b),G(f),G(Kt(BigInt(nn))),G(h)]),A={...k.transaction,inputs:k.transaction.inputs.map((E,C)=>C===0?{...E,unlockingBytecode:R}:E)},v=rn(A);return{name:c,transaction:A,sourceOutputs:S.sourceOutputs,hex:tt(v),txid:tt(ge(v).slice().reverse())}}function Ko(t,{oraclePk:e}={}){let n=o=>({ok:!1,error:o});try{if(t?.kind!=="usd"||t.v!==No)return n("not a v2 usd listing");for(let r of["name","seller","seller_pkh","category","target_cents","floor_sats","ceil_sats","max_age_secs","oracle_pk","redeem_hex","covenant_address","outpoint","token"])if(t[r]==null)return n("missing "+r);if(e&&t.oracle_pk!==e)return n("listing was made for a different oracle key");let o=ye({oraclePk:t.oracle_pk,sellerPkh:t.seller_pkh,targetCents:t.target_cents,floorSats:t.floor_sats,ceilSats:t.ceil_sats,maxAgeSecs:t.max_age_secs});if(tt(o)!==t.redeem_hex)return n("redeem script does not match the stated terms");let s=String(t.seller).split(":")[0]||T.prefix;return we(o,s)!==t.covenant_address?n("covenant address does not match"):tt(Oo(Y(t.seller_pkh))).length!==40?n("bad seller pkh"):t.token?.category!==t.category||!t.token?.nft?n("token does not match category"):Y(t.token.nft.commitment||"").length===0||tt(new TextEncoder().encode(H(t.name)))!==t.token.nft.commitment?n("commitment does not match the name"):{ok:!0,name:H(t.name),covenant_lock:tt(Wt(o))}}catch(o){return n(String(o?.message||o))}}import{hash160 as Wo,lockingBytecodeToCashAddress as Go,binToHex as js}from"@bitauth/libauth";function dn(t){return Uint8Array.from([118,169,20,...Wo(t),136,172])}function zo(t,e=T.prefix,n=!1){let o=Go({bytecode:dn(t),prefix:e,tokenSupport:n});if(typeof o=="string")throw new Error(`address encoding failed: ${o}`);return o.address}function qo(t){return t?{ready:!0,approvals:1,explanation:"Your wallet can mint the certificate directly."}:{ready:!1,approvals:2,explanation:"Your wallet needs one small setup transaction to itself before it can create a certificate \u2014 a rule of the Bitcoin Cash token system, not a fee we charge. You will be asked to approve it, then the registration. This happens only once."}}import{binToHex as lr,hexToBin as ur}from"@bitauth/libauth";import{stringify as hr}from"@bitauth/libauth";export{Jt as BuiltInWallet,Dn as CHIPNET_PREFIX,me as DEFAULT_MAX_AGE_SECS,Se as DEFAULT_NETWORK_ID,At as DEFAULT_PREFIX,J as InsufficientFundsError,Cn as MAINNET_PREFIX,T as NETWORK,kt as NETWORKS,Lt as NoGenesisInputError,D as REGISTRAR,ne as TLD_BEACON,L as addressToLockingBytecode,Wn as addressToScripthash,lr as binToHex,st as broadcast,fo as buildCosignRequest,bt as buildIndex,to as buildListing,Et as buildPrepTx,re as buildRegistrationTx,Ct as buildTldRegistrationTx,Ut as buildUpdateTx,Mo as buildUsdBuyTx,Ho as buildUsdCancelTx,$o as buildUsdListingTx,$t as checkAvailability,oo as completeSale,po as connect,qo as describeGenesisRequirement,Q as displayName,ko as findCertificateUtxo,Qe as findTldCertificateUtxo,Xe as findTldOwnerAddress,_o as getBalance,Pt as getNetwork,Ce as getUtxos,j as getUtxosForAddresses,mt as hasGenesisInput,ur as hexToBin,H as normalizeName,Tt as normalizeTld,cn as parseOracleMessage,oe as payloadBudget,an as payoutSats,Qn as priceSummary,zo as pubkeyToAddress,dn as pubkeyToLockingBytecode,Mt as quoteRegistration,yo as registerTldWithBuiltInWallet,wo as registerTldWithExternalWallet,mo as registerWithBuiltInWallet,xo as registerWithExternalWallet,zt as requireBeacons,An as resolveName,bo as setRecordsWithBuiltInWallet,So as setRecordsWithExternalWallet,To as setTldRecordsWithBuiltInWallet,go as signCosignRequest,_t as signInputs,Eo as signRecordsManifest,ht as signTransaction,pe as sourceOutputFromJson,he as sourceOutputToJson,Je as splitServiceFee,hr as stringify,z as toTokenAddress,Me as toWcTransactionObject,ae as txidOf,ce as txidOfHex,we as usdListingAddress,ye as usdListingRedeem,Ye as verifyListing,ln as verifyOracleMessage,Ko as verifyUsdListing};
|