buildReleaseTx spends the certificate and writes no token output: the omission is the burn. The certificate's own dust pays the beacon and the fee, so a release needs no other coin. releaseWithBuiltInWallet checks whether the certificate sits in a beacon transaction. One that arrived by a plain transfer cannot be proven burned from the beacon history, so the flow publishes an UPD first and releases its output. Both paths ran on chipnet, and a released name was registered again after its release confirmed. checkAvailability now reports a pending release as not available: a REG broadcast while the release is unconfirmed could be mined beside it and be void, and the buyer would have paid for nothing.
7 lines
64 KiB
JavaScript
7 lines
64 KiB
JavaScript
import{generateBip39Mnemonic as Dn,deriveSeedFromBip39Mnemonic as Ie,deriveHdPrivateNodeFromSeed as Cn,deriveHdPath as Un,secp256k1 as Pe,hash160 as Fn,encodeCashAddress as ds,lockingBytecodeToCashAddress as $n,cashAddressToLockingBytecode as hs,binToHex as Mn,hexToBin as ps,utf8ToBin as Le,binToBase64 as Yt,base64ToBin as Vt}from"@bitauth/libauth";var St={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://dl.silentmode.st/bns-name-snapshot.json",nameListMirrorUrl:"https://navigate.st/bns/silentmode.bch/bns-name-snapshot.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}},Ee="chipnet";function wn(){let t=typeof globalThis<"u"?globalThis.BNS_NETWORK:null,e=typeof process<"u"&&process.env?process.env.BNS_NETWORK:null;return String(t||e||Ee).trim().toLowerCase()}function Rt(t){if(t&&typeof t=="object")return t;let e=t||wn(),n=St[e];if(!n)throw new Error(`unknown network "${e}" (known: ${Object.keys(St).join(", ")})`);return n}var O=Rt();function jt(t=O){let e=Rt(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 ts=O.beacon,es=O.beaconScripthash,ns=O.tldBeacon,os=O.tldBeaconScripthash,ss=O.electrum,rs=St.chipnet.electrum,is=O.electrumListName,Se="BNS1";var Oe="bch",xn=/^[a-z0-9-]{1,32}$/,_e=/^[a-z0-9-]{1,16}$/,kn=/^[a-z0-9-]{1,32}(\.[a-z0-9-]{1,16})?$/;function bn(t){return t.includes(".")?t:t+"."+Oe}var Sn=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},zt=t=>[...new TextEncoder().encode(t)].map(e=>e.toString(16).padStart(2,"0")).join("");function Tn(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=Oe):(s=n[n.length-1],o=n[n.length-2]),!xn.test(o)||!_e.test(s))throw new Error(`invalid name "${t}" (allowed: <label>.<tld>, [a-z0-9-])`);return`${o}.${s}`}var Nt=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{}}},En=t=>typeof t=="string"?{url:t}:t;async function On(t,e,{directIP:n=!1}={}){let o;for(let s of t){let r=En(s);try{return await new Nt(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 Nt(i,e,{servername:a.hostname}).connect()}catch(a){o=a}}throw o??new Error("no electrum server reachable")}function ve(t){if(!t||!t.startsWith("6a"))return null;let e=Sn(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(Se))return null;try{let r=JSON.parse(s.slice(Se.length));if(_n.has(r.o)&&typeof r.n=="string")return r}catch{}return null}var _n=new Set(["REG","UPD","REL","TREG","TUPD"]);function Ae(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 Be(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 vn(t,e,n){let o=n.get(t);return o?o.regHeight>0&&e>0?o.regHeight<=e:!0:!1}async function qt(t,e=O){let{tldBeaconScripthash:n}=jt(e),o=typeof t.unionHistory=="function"?(await t.unionHistory(n)).history:await t.call("blockchain.scripthash.get_history",[n]);o.sort(Ae);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 Be(o.filter(l=>s.has(l.tx_hash)),s)){let c=s.get(a).vout||[],h=null;for(let u of c)h=ve(u.scriptPubKey?.hex)??h;if(!h||typeof h.n!="string"||!_e.test(h.n))continue;let d=h.n;if(h.o==="TREG"){if(r.has(d))continue;let u=zt(d),f=c.find(m=>m.tokenData?.nft&&m.tokenData.nft.commitment===u);if(!f)continue;r.set(d,{category:f.tokenData.category,regHeight:i,regTxid:a,mintScriptHex:f.scriptPubKey?.hex??null,records:h.r??{},updates:[{height:i,txid:a,records:h.r??{}}]})}else if(h.o==="TUPD"){let u=r.get(d);if(!u||!c.some(f=>f.tokenData&&f.tokenData.category===u.category))continue;u.records=h.r??{},u.updates.push({height:i,txid:a,records:u.records})}}return r}function An(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 Bn(t,e){let n=An(t,e);return n.policy==="cosign"||n.hidden===1||n.hidden===!0||n.hidden==="1"}function In(t,e,n){let o=zt(n);return(t||[]).some(s=>s.tokenData&&s.tokenData.category===e.category&&s.tokenData.nft&&s.tokenData.nft.commitment===o)}function Te(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}function Pn(t,e){let n=t&&t.txid?e.get(t.txid):null;return!n||!Array.isArray(n.vout)?null:n.vout.find(o=>o&&o.n===t.vout)??n.vout[t.vout]??null}function Nn(t,e,n){return!t||!e||!e.category||(t.vout||[]).some(o=>o.tokenData&&o.tokenData.category===e.category)?!1:(t.vin||[]).some(o=>{let s=Pn(o,n);return!!(s&&s.tokenData&&s.tokenData.nft&&s.tokenData.category===e.category)})}function Rn(t,e){return t===void 0?!0:t>0?!(e>0)||e>t:!1}async function yt({network:t=O,electrum:e=Rt(t).electrum,WebSocket:n,client:o,directIP:s=!1,enforceTld:r=!1,cosignGate:a=!0}={}){let i=jt(t),l=o??await On(e,n,{directIP:s});try{let c=null;if(r||a)try{c=await qt(l,i)}catch(p){if(r)throw p;c=null}let h=null,d;if(typeof l.unionHistory=="function"){let p=await l.unionHistory(i.beaconScripthash);d=p.history,h={servers:p.servers,unreachable:p.unreachable,disagreements:p.disagreements}}else d=await l.call("blockchain.scripthash.get_history",[i.beaconScripthash]);d.sort(Ae);let u=new Map;for(let{tx_hash:p}of d)try{u.set(p,await l.call("blockchain.transaction.get",[p,!0]))}catch{}let f=new Map,m=new Map;for(let{tx_hash:p,height:g}of Be(d.filter(y=>u.has(y.tx_hash)),u)){let y=u.get(p),w=y.vout||[],x=null;for(let k of w)x=ve(k.scriptPubKey?.hex)??x;if(!x)continue;let v=x.n;if(!kn.test(v))continue;let b=bn(v);if(x.o==="REG"){if(f.has(b)||!Rn(m.get(b),g)||r&&!vn(Gt(b),g,c))continue;if(a&&c){let T=c.get(Gt(b));if(T&&Bn(T,g)&&!In(w,T,Gt(b)))continue}let k=zt(v),B=w.find(T=>T.tokenData?.nft&&T.tokenData.nft.commitment===k);if(!B)continue;f.set(b,{name:b,category:B.tokenData.category,records:x.r??{},txid:p,height:g,updatedTxid:null,owner:Te(B)}),m.delete(b)}else if(x.o==="REL"){let k=f.get(b);if(!k||!Nn(y,k,u))continue;f.delete(b),m.set(b,g)}else if(x.o==="UPD"){let k=f.get(b);if(!k)continue;let B=w.find(T=>T.tokenData&&T.tokenData.category===k.category);if(!B)continue;k.records=x.r??{},k.updatedTxid=p,k.owner=Te(B)??k.owner}}return h&&Object.defineProperty(f,"integrity",{value:h,enumerable:!1}),Object.defineProperty(f,"released",{value:m,enumerable:!1}),f}finally{o||l.close()}}async function Ln(t,e={}){let n=Tn(t);return(await yt(e)).get(n)??null}var as=O.rootTldName,cs=O.bootstrapTlds.slice();var Hn="bchtest",Kn="bitcoincash",At=O.prefix,Xt="m/44'/145'/0'",Wn=5,Lt="bns.wallet.v1";function De(t){let e=Fn(t);return Uint8Array.from([118,169,20,...e,136,172])}function Ne(t,e,n){let o=$n({bytecode:De(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=Cn(n),this._keys=new Map,this._derive()}static async create(e=At,n=Xt){let o=Dn();return new t(o,await Ie(o),e,n)}static async fromMnemonic(e,n=At,o=Xt){let s=String(e).trim().toLowerCase().replace(/\s+/g," "),r=await Ie(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<Wn;o++){let s=`${this.accountPath}/${e}/${o}`,r=Un(this._root,s);if(typeof r=="string")throw new Error(`HD derivation failed at ${s}: ${r}`);let a=Pe.derivePublicKeyCompressed(r.privateKey);if(typeof a=="string")throw new Error(`pubkey derivation failed: ${a}`);let i=De(a),l={path:s,branch:e,index:o,privateKey:r.privateKey,publicKey:a,lockingBytecode:i,address:Ne(a,this.prefix,!1),tokenAddress:Ne(a,this.prefix,!0)};n.push(l),this._keys.set(Mn(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=Pe.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 Re(e,n),r=new Uint8Array(await crypto.subtle.encrypt({name:"AES-GCM",iv:o},s,Le(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 Re(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(Lt,await this.encrypt(e))}static async load(e,n=globalThis.localStorage){let o=n.getItem(Lt);return o?t.decrypt(o,e):null}static exists(e=globalThis.localStorage){return!!e?.getItem(Lt)}static forget(e=globalThis.localStorage){e.removeItem(Lt)}},Qt=25e4;async function Re(t,e,n=Qt){let o=await crypto.subtle.importKey("raw",Le(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 ys=St.chipnet.electrum.map(t=>t.url),Dt=O.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 Ce(t=Dt,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 Gn(t.length,n)}function Gn(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 jn,lockingBytecodeToCashAddress as zn,sha256 as qn,hash160 as ks,binToHex as Yn,hexToBin as bs}from"@bitauth/libauth";function Ue(t){return Yn(qn.hash(t).slice().reverse())}function D(t){let e=jn(t);if(typeof e=="string")throw new Error(`bad address "${t}": ${e}`);return e.bytecode}function Vn(t){return Ue(D(t))}function j(t){let e=D(t),n=String(t).includes(":")?t.split(":")[0]:O.prefix,o=zn({bytecode:e,prefix:n,tokenSupport:!0});if(typeof o=="string")throw new Error(`cannot token-encode "${t}": ${o}`);return o.address}async function Fe(t,e){let n=D(e),o=Ue(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 z(t,e){let n=[];for(let o of e)n.push(...await Fe(t,o));return n}async function tt(t,e){return t.call("blockchain.transaction.broadcast",[e])}async function $e(t,e,n=!0){return t.call("blockchain.transaction.get",[e,n])}import{binToHex as Bt,hexToBin as V,utf8ToBin as pt,binToUtf8 as ne,encodeTransaction as Xn,decodeTransaction as Os}from"@bitauth/libauth";var Jn="BNS1",at=O.beacon,oe=O.tldBeacon,A=600n,R=1000n,K=546n,te="bch",ee=200,Qn=/^[a-z0-9-]{1,32}$/,Me=/^[a-z0-9-]{1,16}$/;function Tt(t){let e=String(t).toLowerCase().trim().replace(/^\.+/,"").replace(/\.+$/,"");if(!Me.test(e))throw new Error(`invalid TLD "${t}" (allowed: [a-z0-9-]{1,16})`);return e}var Ct=class extends Error{constructor(e){super(e),this.name="NoGenesisInputError",this.code="NO_GENESIS_INPUT"}},X=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 C(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)||!Me.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 J(t,e,n){let o=JSON.stringify({o:t,n:e,r:n??{}}),s=pt(Jn+o);if(s.length>ee)throw new Error(`records too large (${s.length} > ${ee} bytes)`);return s}function se(t,e="REG"){return ee-J(e,t,{}).length}function Zn(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,...Zn(t)])}function re(){return Uint8Array.from([65,...new Uint8Array(65),33,...new Uint8Array(33)])}var to=t=>!t.token;function F(t,e,{requireGenesis:n=!0}={}){let o=t.filter(to),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 Ct("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 ft(t){return{outpointTransactionHash:V(t.txid),outpointIndex:t.vout,sequenceNumber:4294967294,unlockingBytecode:re()}}function wt(t){return{...ft(t),lockingBytecode:t.lockingBytecode,valueSatoshis:t.satoshis,...t.token?{token:{amount:t.token.amount??0n,category:V(t.token.category),...t.token.nft?{nft:{capability:t.token.nft.capability,commitment:V(t.token.nft.commitment||"")}}:{}}}:{}}}function ot(t){return Xn(t).length}function ie({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=at,feeRate:d=1,addressToLockingBytecode:u,cosignUtxo:f=null,cosignTokenAddress:m=null}){if(typeof u!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let p=C(t),g=J("REG",p,s),y=BigInt(i??0n),w=BigInt(c??0n);if(f&&!f.token?.nft)throw new Error("cosignUtxo does not carry a TLD certificate");let x=f?BigInt(f.satoshis):0n,v=f?u(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 b=u(o??e),k=u(n??e),B=u(h),T=y>0n?u(a):null,S=w>0n?u(l):null,P=R+A+y+w+x,I=F(r,P+300n-x),E=0n,_=0n,U=!0;for(let N=0;N<6;N++){let{inputs:M}=I,H=f?[...M,f]:M,W=I.totalSats+x,dt=H[0],it=V(dt.txid),Y=(kt,bt)=>{let Z=[];return kt&&Z.push({lockingBytecode:b,valueSatoshis:bt}),Z.push({lockingBytecode:k,valueSatoshis:R,token:{amount:0n,category:it,nft:{capability:"none",commitment:pt(p)}}}),Z.push({lockingBytecode:et(g),valueSatoshis:0n}),Z.push({lockingBytecode:B,valueSatoshis:A}),S&&Z.push({lockingBytecode:S,valueSatoshis:w}),T&&Z.push({lockingBytecode:T,valueSatoshis:y}),f&&Z.push({lockingBytecode:v,valueSatoshis:x,token:{amount:BigInt(f.token.amount??0),category:V(f.token.category),nft:{capability:f.token.nft.capability,commitment:V(f.token.nft.commitment||"")}}}),{version:2,locktime:0,inputs:H.map(ft),outputs:Z}},gn=Y(!0,1000000n),mn=ot(gn);E=BigInt(Math.ceil(mn*d));let vt=P+E;if(W<vt){let kt=F(r,vt+200n-x);if(kt.inputs.length>M.length){I=kt;continue}throw new X(`not enough funds: need ${vt} sat, have ${W} sat`,{needSats:vt,haveSats:W})}if(_=W-vt,U=_>=K,!U){let kt=Y(!1,0n);E=W-P;let bt=BigInt(Math.ceil(ot(kt)*d));if(E<bt){let Z=F(r,P+bt+K+200n-x);if(Z.inputs.length>M.length){I=Z;continue}throw new X(`not enough funds: need ${P+bt} sat, have ${W} sat`,{needSats:P+bt,haveSats:W})}_=0n}let yn=Y(U,_),ht={},mt=0;return U&&(ht.change=mt++),ht.certificate=mt++,ht.opReturn=mt++,ht.beacon=mt++,S&&(ht.tldOwnerFee=mt++),T&&(ht.serviceFee=mt++),f&&(ht.cosignCertificate=mt++),{name:p,displayName:q(p),category:Bt(it),transaction:yn,sourceOutputs:H.map(wt),inputUtxos:H,outputMap:ht,payload:g,costs:{certificateDustSats:R,beaconDustSats:A,serviceFeeSats:y,tldOwnerFeeSats:w,chainFeeSats:E,changeSats:_,totalInputSats:W,netCostSats:y+w+E+A}}}throw new Error("could not converge on a fee \u2014 please retry")}function Ut({tld:t,ownerAddress:e,ownerTokenAddress:n,changeAddress:o,records:s={},utxos:r,feeAddress:a=null,feeSats:i=0n,beaconAddress:l=oe,feeRate:c=1,addressToLockingBytecode:h}){if(typeof h!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let d=Tt(t),u=J("TREG",d,s),f=BigInt(i??0n);if(f>0n&&!a)throw new Error("feeSats set but feeAddress missing");let m=h(o??e),p=h(n??e),g=h(l),y=f>0n?h(a):null,w=R+A+f,x=F(r,w+300n),v=0n,b=0n,k=!0;for(let B=0;B<6;B++){let{inputs:T,totalSats:S}=x,P=T[0],I=V(P.txid),E=(dt,it)=>{let Y=[];return dt&&Y.push({lockingBytecode:m,valueSatoshis:it}),Y.push({lockingBytecode:p,valueSatoshis:R,token:{amount:0n,category:I,nft:{capability:"none",commitment:pt(d)}}}),Y.push({lockingBytecode:et(u),valueSatoshis:0n}),Y.push({lockingBytecode:g,valueSatoshis:A}),y&&Y.push({lockingBytecode:y,valueSatoshis:f}),{version:2,locktime:0,inputs:T.map(ft),outputs:Y}},_=E(!0,1000000n),U=ot(_);v=BigInt(Math.ceil(U*c));let N=w+v;if(S<N){let dt=F(r,N+200n);if(dt.inputs.length>T.length){x=dt;continue}throw new X(`not enough funds: need ${N} sat, have ${S} sat`,{needSats:N,haveSats:S})}if(b=S-N,k=b>=K,!k){let dt=E(!1,0n);v=S-w;let it=BigInt(Math.ceil(ot(dt)*c));if(v<it){let Y=F(r,w+it+K+200n);if(Y.inputs.length>T.length){x=Y;continue}throw new X(`not enough funds: need ${w+it} sat, have ${S} sat`,{needSats:w+it,haveSats:S})}b=0n}let M=E(k,b),H={},W=0;return k&&(H.change=W++),H.certificate=W++,H.opReturn=W++,H.beacon=W++,y&&(H.serviceFee=W++),{tld:d,category:Bt(I),transaction:M,sourceOutputs:T.map(wt),inputUtxos:T,outputMap:H,payload:u,costs:{certificateDustSats:R,beaconDustSats:A,serviceFeeSats:f,chainFeeSats:v,changeSats:b,totalInputSats:S,netCostSats:f+v+A}}}throw new Error("could not converge on a fee \u2014 please retry")}function It({name:t,ownerAddress:e,ownerTokenAddress:n,records:o={},certificateUtxo:s,utxos:r,beaconAddress:a=at,feeRate:i=1,addressToLockingBytecode:l}){if(typeof l!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let c=C(t);if(!s?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");let h=Bt(pt(c));if(s.token.nft.commitment!==h)throw new Error(`certificate commitment mismatch: holds "${ne(V(s.token.nft.commitment))}", asked to update "${c}"`);let d=J("UPD",c,o),u=l(e),f=l(n??e),m=l(a),p=R+A,g=F(r,p+400n,{requireGenesis:!1}),y=0n,w=0n,x=!0;for(let v=0;v<6;v++){let b=[s,...g.inputs],k=s.satoshis+g.totalSats,B=(_,U)=>{let N=[];return _&&N.push({lockingBytecode:u,valueSatoshis:U}),N.push({lockingBytecode:f,valueSatoshis:R,token:{amount:0n,category:V(s.token.category),nft:{capability:"none",commitment:pt(c)}}}),N.push({lockingBytecode:et(d),valueSatoshis:0n}),N.push({lockingBytecode:m,valueSatoshis:A}),{version:2,locktime:0,inputs:b.map(ft),outputs:N}},T=ot(B(!0,1000000n));y=BigInt(Math.ceil(T*i));let S=p+y;if(k<S){let _=F(r,S+200n,{requireGenesis:!1});if(_.inputs.length>g.inputs.length){g=_;continue}throw new X(`not enough funds: need ${S} sat, have ${k} sat`,{needSats:S,haveSats:k})}w=k-S,x=w>=K,x||(y=k-p,w=0n);let P=B(x,w),I={},E=0;return x&&(I.change=E++),I.certificate=E++,I.opReturn=E++,I.beacon=E++,{name:c,displayName:q(c),category:s.token.category,transaction:P,sourceOutputs:b.map(wt),inputUtxos:b,outputMap:I,payload:d,costs:{certificateDustSats:R,beaconDustSats:A,serviceFeeSats:0n,chainFeeSats:y,changeSats:w,totalInputSats:k,netCostSats:y+A}}}throw new Error("could not converge on a fee \u2014 please retry")}function ae({name:t,ownerAddress:e,certificateUtxo:n,utxos:o=[],beaconAddress:s=at,feeRate:r=1,addressToLockingBytecode:a}){if(typeof a!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let i=C(t);if(!n?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");let l=Bt(pt(i));if(n.token.nft.commitment!==l)throw new Error(`certificate commitment mismatch: holds "${ne(V(n.token.nft.commitment))}", asked to release "${i}"`);let c=J("REL",i,{}),h=a(e),d=a(s),u=A,f={inputs:[],totalSats:0n},m=0n,p=0n,g=!0;for(let y=0;y<6;y++){let w=[n,...f.inputs],x=n.satoshis+f.totalSats,v=(P,I)=>{let E=[];return P&&E.push({lockingBytecode:h,valueSatoshis:I}),E.push({lockingBytecode:et(c),valueSatoshis:0n}),E.push({lockingBytecode:d,valueSatoshis:A}),{version:2,locktime:0,inputs:w.map(ft),outputs:E}},b=BigInt(Math.ceil(ot(v(!1,0n))*r)),k=BigInt(Math.ceil(ot(v(!0,1000000n))*r));if(x<u+b){let P=F(o,u+k+200n,{requireGenesis:!1});if(P.inputs.length>f.inputs.length){f=P;continue}throw new X(`not enough funds: need ${u+b} sat, have ${x} sat`,{needSats:u+b,haveSats:x})}p=x-u-k,g=p>=K,g?m=k:(m=x-u,p=0n);let B=v(g,p),T={},S=0;return g&&(T.change=S++),T.opReturn=S++,T.beacon=S++,{name:i,displayName:q(i),category:n.token.category,transaction:B,sourceOutputs:w.map(wt),inputUtxos:w,outputMap:T,payload:c,costs:{beaconDustSats:A,chainFeeSats:m,changeSats:p,totalInputSats:x,netCostSats:m+A}}}throw new Error("could not converge on a fee \u2014 please retry")}function He({tld:t,ownerAddress:e,ownerTokenAddress:n,records:o={},certificateUtxo:s,utxos:r,beaconAddress:a=oe,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=Bt(pt(c));if(s.token.nft.commitment!==h)throw new Error(`TLD certificate commitment mismatch: holds "${ne(V(s.token.nft.commitment))}", asked to update ".${c}"`);let d=J("TUPD",c,o),u=l(e),f=l(n??e),m=l(a),p=R+A,g=F(r,p+400n,{requireGenesis:!1}),y=0n,w=0n,x=!0;for(let v=0;v<6;v++){let b=[s,...g.inputs],k=s.satoshis+g.totalSats,B=(_,U)=>{let N=[];return _&&N.push({lockingBytecode:u,valueSatoshis:U}),N.push({lockingBytecode:f,valueSatoshis:R,token:{amount:0n,category:V(s.token.category),nft:{capability:"none",commitment:pt(c)}}}),N.push({lockingBytecode:et(d),valueSatoshis:0n}),N.push({lockingBytecode:m,valueSatoshis:A}),{version:2,locktime:0,inputs:b.map(ft),outputs:N}},T=ot(B(!0,1000000n));y=BigInt(Math.ceil(T*i));let S=p+y;if(k<S){let _=F(r,S+200n,{requireGenesis:!1});if(_.inputs.length>g.inputs.length){g=_;continue}throw new X(`not enough funds: need ${S} sat, have ${k} sat`,{needSats:S,haveSats:k})}w=k-S,x=w>=K,x||(y=k-p,w=0n);let P=B(x,w),I={},E=0;return x&&(I.change=E++),I.certificate=E++,I.opReturn=E++,I.beacon=E++,{tld:c,displayName:`.${c}`,category:s.token.category,transaction:P,sourceOutputs:b.map(wt),inputUtxos:b,outputMap:I,payload:d,costs:{certificateDustSats:R,beaconDustSats:A,serviceFeeSats:0n,chainFeeSats:y,changeSats:w,totalInputSats:k,netCostSats:y+A}}}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=F(e,n+400n,{requireGenesis:!1});if(a.inputs.length===0)throw new X("wallet is empty");for(let i=0;i<6;i++){let{inputs:l,totalSats:c}=a,h=(m,p)=>({version:2,locktime:0,inputs:l.map(ft),outputs:[{lockingBytecode:r,valueSatoshis:n},...m?[{lockingBytecode:r,valueSatoshis:p}]:[]]}),d=BigInt(Math.ceil(ot(h(!0,1000000n))*o));if(c<n+d){let m=BigInt(Math.ceil(ot(h(!1,0n))*o));if(c<=m+K)throw new X(`not enough funds to prepare the wallet: have ${c} sat`,{needSats:m+K,haveSats:c});return{transaction:{version:2,locktime:0,inputs:l.map(ft),outputs:[{lockingBytecode:r,valueSatoshis:c-m}]},sourceOutputs:l.map(wt),inputUtxos:l,costs:{chainFeeSats:m}}}let u=c-n-d,f=u>=K;return{transaction:h(f,u),sourceOutputs:l.map(wt),inputUtxos:l,costs:{chainFeeSats:f?d:c-n}}}throw new Error("could not converge on a fee \u2014 please retry")}function xt(t){return t.some(e=>e.vout===0&&!e.token)}function Ke({transaction:t,sourceOutputs:e},{broadcast:n=!0,userPrompt:o}={}){return{transaction:t,sourceOutputs:e,broadcast:n,...o?{userPrompt:o}:{}}}import{generateSigningSerializationBCH as eo,hash256 as Ge,secp256k1 as no,encodeTransaction as oo,binToHex as ce}from"@bitauth/libauth";var We=65;function st(t,e,n){let o={...t,inputs:t.inputs.map((r,a)=>{let i=e[a],l=n(ce(i.lockingBytecode));if(!l)throw new Error(`no key for input ${a} \u2014 cannot sign`);let c=eo({inputIndex:a,sourceOutputs:e,transaction:t},{coveredBytecode:i.lockingBytecode,signingSerializationType:Uint8Array.of(We)}),h=Ge(c),d=no.signMessageHashSchnorr(l.privateKey,h);if(typeof d=="string")throw new Error(`signing failed on input ${a}: ${d}`);let u=Uint8Array.from([...d,We]);return{...r,unlockingBytecode:Uint8Array.from([u.length,...u,l.publicKey.length,...l.publicKey])}})},s=oo(o);return{transaction:o,hex:ce(s),txid:le(s)}}function le(t){return ce(Ge(t).slice().reverse())}function ue(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 le(e)}var L={network:O.id,addressPrefix:O.prefix,explorerTx:O.explorerTx,selfHosted:null,get electrum(){return this.selfHosted?[this.selfHosted,...Dt]:Dt},beacon:O.beacon,tldBeacon:O.tldBeacon,serviceFee:{address:O.operatorAddress,sats:10000n},feeRate:1,wizardConnect:{dappName:"Silent Mode",dappIcon:"https://silentmode.st/icon.png"},faucets:O.faucets};function so(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 Je,binToHex as gt,decodeTransaction as uo,lockingBytecodeToCashAddress as ho,sha256 as po,utf8ToBin as fo,binToBase64 as go}from"@bitauth/libauth";import{encodeTransaction as he,decodeTransaction as je,generateSigningSerializationBCH as ze,hash256 as pe,hash160 as ro,secp256k1 as qe,hexToBin as ct,binToHex as $,utf8ToBin as Ye}from"@bitauth/libauth";var Ft=65,de=195,rt=(t,e)=>({outpointTransactionHash:ct(t.txid),outpointIndex:t.vout,sequenceNumber:4294967294,unlockingBytecode:e??re()}),lt=t=>t?{amount:BigInt(t.amount??0),category:ct(t.category),...t.nft?{nft:{capability:t.nft.capability,commitment:ct(t.nft.commitment||"")}}:{}}:void 0,fe=t=>({lockingBytecode:t.lockingBytecode instanceof Uint8Array?$(t.lockingBytecode):String(t.lockingBytecode),valueSatoshis:String(t.valueSatoshis),...t.token?{token:{category:t.token.category instanceof Uint8Array?$(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?$(t.token.nft.commitment):String(t.token.nft.commitment||"")}}:{}}}:{}}),ge=t=>({lockingBytecode:ct(t.lockingBytecode),valueSatoshis:BigInt(t.valueSatoshis??t.satoshis),...t.token?{token:lt(t.token)}:{}}),ut=(t,e)=>({...rt(t,e),lockingBytecode:t.lockingBytecode instanceof Uint8Array?t.lockingBytecode:ct(t.lockingBytecode),valueSatoshis:BigInt(t.satoshis),...t.token?{token:lt(t.token)}:{}});function Ve(t,e,n,o,s){let r=e[n],a=ze({inputIndex:n,sourceOutputs:e,transaction:t},{coveredBytecode:r.lockingBytecode,signingSerializationType:Uint8Array.of(s)}),i=pe(a),l=qe.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 Ot(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($(e[l].lockingBytecode));return c?{...i,unlockingBytecode:Ve(t,e,l,c,o)}:i})},a=he(r);return{transaction:r,hex:$(a),txid:$(pe(a).slice().reverse())}}function io({name:t,certificateUtxo:e,priceSats:n,sellerAddress:o,addressToLockingBytecode:s,keyFor:r}){let a=C(t),i=BigInt(n);if(i<K)throw new Error(`price must be at least ${K} sat`);if(!e?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");if(e.token.nft.commitment!==$(Ye(a)))throw new Error("certificate commitment does not match the name");let l=s(o),c=ut(e),h={version:2,locktime:0,inputs:[rt(e)],outputs:[{lockingBytecode:l,valueSatoshis:i}]},d=r($(c.lockingBytecode));if(!d)throw new Error("this wallet does not hold the key for the certificate");return h.inputs[0].unlockingBytecode=Ve(h,[c],0,d,de),{v:1,name:a,seller:o,price_sats:i.toString(),category:e.token.category,partial_tx:$(he(h)),source_output:{txid:e.txid,vout:e.vout,satoshis:BigInt(e.satoshis).toString(),lockingBytecode:$(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 ao(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 co=t=>Uint8Array.from([118,169,20,...ro(t),136,172]);function Xe(t,e={}){let n=o=>({ok:!1,error:o});try{if(!t||t.v!==1)return n("unsupported listing version");let o=C(t.name),s=je(ct(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($(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!==$(Ye(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<K)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}=ao(s.inputs[0].unlockingBytecode);if(i.length!==65||i[64]!==de)return n("input 0 is not signed SINGLE|ANYONECANPAY");let c=ct(r.lockingBytecode);if($(co(l))!==$(c))return n("public key does not own the certificate output");if(e.ownerLockingBytecode&&$(c)!==e.ownerLockingBytecode)return n("certificate is not held by the current owner");if($(s.outputs[0].lockingBytecode)!==$(c))return n("payment does not go to the certificate holder");let h={...s.inputs[0],lockingBytecode:c,valueSatoshis:BigInt(r.satoshis),token:lt(r.token)},d=ze({inputIndex:0,sourceOutputs:[h],transaction:s},{coveredBytecode:c,signingSerializationType:Uint8Array.of(de)});return qe.verifySignatureSchnorr(i.slice(0,64),l,pe(d))?{ok:!0,name:o,price_sats:a,seller_lock:$(c),category:r.token.category}:n("seller signature is invalid")}catch(o){return n(String(o?.message||o))}}function lo({listing:t,buyerAddress:e,buyerTokenAddress:n,utxos:o,records:s={},beaconAddress:r=at,feeRate:a=1,addressToLockingBytecode:i}){let l=Xe(t);if(!l.ok)throw new Error("bad listing: "+l.error);let c=l.name,h=je(ct(t.partial_tx)),d=t.source_output,u=h.inputs[0],f={...u,lockingBytecode:ct(d.lockingBytecode),valueSatoshis:BigInt(d.satoshis),token:lt(d.token)},m=h.outputs[0],p=m.valueSatoshis,g=i(e),y=i(n??e),w=i(r),x=J("UPD",c,s),v=p+R+A-BigInt(d.satoshis),b=F(o,v+400n,{requireGenesis:!1}),k=B=>he(B).length;for(let B=0;B<6;B++){let{inputs:T,totalSats:S}=b,P=(M,H)=>({version:2,locktime:0,inputs:[u,...T.map(W=>rt(W))],outputs:[m,{lockingBytecode:y,valueSatoshis:R,token:lt(d.token)},{lockingBytecode:et(x),valueSatoshis:0n},{lockingBytecode:w,valueSatoshis:A},...M?[{lockingBytecode:g,valueSatoshis:H}]:[]]}),I=BigInt(Math.ceil(k(P(!0,1000000n))*a)),E=v+I;if(S<E){let M=F(o,E+200n,{requireGenesis:!1});if(M.inputs.length>T.length){b=M;continue}let H=new Error(`not enough funds: need ${E} sat, have ${S} sat`);throw H.needSats=E,H.haveSats=S,H}let _=S-E,U=_>=K;U||(_=0n);let N=P(U,_);return{name:c,transaction:N,sourceOutputs:[f,...T.map(M=>ut(M))],sellerInputIndex:0,costs:{priceSats:p,beaconDustSats:A,certificateDustSats:R,chainFeeSats:U?I:S-v,changeSats:_,totalInputSats:S}}}throw new Error("could not converge on a fee \u2014 please retry")}var mo=90n,yo=100n;async function Qe(t,e,n=L.addressPrefix){let s=(await qt(t)).get(String(e).toLowerCase());if(!s?.mintScriptHex)return null;try{let r=Je(s.mintScriptHex),a=ho({bytecode:r,prefix:n,tokenSupport:!1});return typeof a=="string"?null:a.address}catch{return null}}function Ze(t){let e=BigInt(t??0n),n=e*mo/yo,o=e-n;return{tldOwnerFeeSats:n,platformFeeSats:o}}var wo=O.beaconOnly;async function xo({electrum:t=L.electrum,WebSocket:e,beaconOk:n=!1}={}){let o=n?t:t.filter(s=>!wo.test(typeof s=="string"?s:s.url||""));return Ce(o,e)}async function $t(t,e){let n=C(e),o=q(n),s=await yt({client:t}),r=s.get(o)??null,a=s.released?.get(o),i=a!==void 0&&!(a>0);return{name:o,rawName:n,available:!r&&!i,entry:r,releasedAt:a??null,releasePending:i,reason:r?"registered":i?"release-pending":null,recordBudgetBytes:se(n)}}async function Mt(t,{name:e,ownerAddress:n,records:o={},utxos:s,serviceFee:r=L.serviceFee,feeRate:a=L.feeRate,cosignUtxo:i=null,cosignTokenAddress:l=null}){let c=s??await z(t,[n]),h=C(e),d=h.indexOf("."),u=d<0?"bch":h.slice(d+1),f=BigInt(r.sats??0n),m=null,p=0n,g=f;if(f>0n){try{m=await Qe(t,u)}catch{m=null}if(m&&m!==n){let y=Ze(f);p=y.tldOwnerFeeSats,g=y.platformFeeSats}}return ie({name:e,ownerAddress:n,ownerTokenAddress:j(n),records:o,utxos:c,feeAddress:g>0n?r.address:null,feeSats:g,tldFeeAddress:p>0n?m:null,tldFeeSats:p,beaconAddress:L.beacon,feeRate:a,addressToLockingBytecode:D,cosignUtxo:i,cosignTokenAddress:l})}function tn(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 en(t,{wallet:e,utxos:n,feeRate:o,onProgress:s}){if(xt(n))return{utxos:n,prepTxid:null};s("preparing-wallet");let r=Et({ownerAddress:e.address,utxos:n,feeRate:o,addressToLockingBytecode:D}),a=st(r.transaction,r.sourceOutputs,c=>e.keyFor(c)),i=await tt(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:D(e.address)})),prepTxid:i}}async function ko(t,{wallet:e,name:n,records:o={},serviceFee:s=L.serviceFee,feeRate:r=L.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.releasePending?`"${l.name}" was just released \u2014 it can be registered once that release is in a block`:`"${l.name}" is already registered`);i("loading-coins");let c=await z(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 d=null;({utxos:c,prepTxid:d}=await en(t,{wallet:e,utxos:c,feeRate:r,onProgress:i})),i("building");let u=await Mt(t,{name:n,ownerAddress:e.address,records:o,utxos:c,serviceFee:s,feeRate:r,cosignUtxo:{...a.utxo,address:a.owner},cosignTokenAddress:j(a.owner)}),f=u.transaction.inputs.length-1;i("signing");let m={...u.transaction,inputs:u.transaction.inputs.map((g,y)=>y===f?{...g,unlockingBytecode:new Uint8Array}:g)},p=Ot(m,u.sourceOutputs,g=>e.keyFor(g),{skip:[f]});return{name:u.name,displayName:u.displayName,category:u.category,tx:p.hex,sourceOutputs:u.sourceOutputs.map(fe),cosignInputIndex:f,costs:u.costs,prepTxid:d}}function bo(t,e){let n=uo(Je(String(t.tx||"")));if(typeof n=="string")throw new Error("invalid transaction: "+n);let o=(t.sourceOutputs||[]).map(ge);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(gt(c.lockingBytecode))){s.push(l);return}if(c.token?.nft&&!n.outputs.some(d=>d.token&>(d.token.category)===gt(c.token.category)&>(d.token.nft?.commitment??new Uint8Array)===gt(c.token.nft.commitment??new Uint8Array)&>(d.lockingBytecode)===gt(c.lockingBytecode)&&d.valueSatoshis>=c.valueSatoshis))throw new Error("refusing to sign: the request would not return your TLD certificate to you");r+=1});let a=Ot(n,o,e,{skip:s});return{hex:a.hex,txid:a.txid,signedInputs:r}}async function So(t,{wallet:e,name:n,records:o={},serviceFee:s=L.serviceFee,feeRate:r=L.feeRate,cosign:a=null,onProgress:i=()=>{}}){i("checking-availability");let l=await $t(t,n);if(!l.available)throw new Error(l.releasePending?`"${l.name}" was just released \u2014 it can be registered once that release is in a block`:`"${l.name}" is already registered`);i("loading-coins");let c=await z(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 d=null;if(a&&(d=tn(c,a),!d))throw new Error(`this wallet does not hold the certificate for .${a.tld} \u2014 only the TLD owner can co-sign`);let u=null;({utxos:c,prepTxid:u}=await en(t,{wallet:e,utxos:c,feeRate:r,onProgress:i})),i("building");let f=await Mt(t,{name:n,ownerAddress:e.address,records:o,utxos:c,serviceFee:s,feeRate:r,cosignUtxo:d,cosignTokenAddress:d?j(e.address):null});i("signing");let m=st(f.transaction,f.sourceOutputs,g=>e.keyFor(g));i("broadcasting");let p=await tt(t,m.hex);return i("registered",{txid:p,category:f.category}),{name:f.name,displayName:f.displayName,category:f.category,txid:p,prepTxid:u,ownerAddress:e.address,certificateAddress:j(e.address),costs:f.costs,hex:m.hex}}async function To(t,{wallet:e,tld:n,records:o={},serviceFee:s={address:null,sats:0n},feeRate:r=L.feeRate,tldListUrl:a=null,onProgress:i=()=>{}}){let l=Tt(n);if(i("checking-availability"),a)try{let p=await fetch(a);if(p.ok){let g=await p.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(p){if(/already registered/.test(p.message))throw p}i("loading-coins");let c=await z(t,e.watchedAddresses);if(c.filter(p=>!p.token).reduce((p,g)=>p+g.satoshis,0n)===0n)throw new Error("wallet is empty \u2014 fund the address first");let d=null;if(!xt(c)){i("preparing-wallet");let p=Et({ownerAddress:e.address,utxos:c,feeRate:r,addressToLockingBytecode:D}),g=st(p.transaction,p.sourceOutputs,y=>e.keyFor(y));d=await tt(t,g.hex),i("prepared",{txid:d}),c=[{txid:d,vout:0,satoshis:g.transaction.outputs[0].valueSatoshis,address:e.address,lockingBytecode:D(e.address)},...g.transaction.outputs.length>1?[{txid:d,vout:1,satoshis:g.transaction.outputs[1].valueSatoshis,address:e.address,lockingBytecode:D(e.address)}]:[]]}i("building");let u=Ut({tld:l,ownerAddress:e.address,ownerTokenAddress:j(e.address),changeAddress:e.address,records:o,utxos:c,feeAddress:s.address||null,feeSats:BigInt(s.sats??0n),feeRate:r,addressToLockingBytecode:D});i("signing");let f=st(u.transaction,u.sourceOutputs,p=>e.keyFor(p));i("broadcasting");let m=await tt(t,f.hex);return i("registered",{txid:m,category:u.category}),{tld:u.tld,category:u.category,txid:m,prepTxid:d,ownerAddress:e.address,certificateAddress:j(e.address),costs:u.costs,hex:f.hex}}async function Eo(t,{session:e,tld:n,records:o={},serviceFee:s={address:null,sats:0n},feeRate:r=L.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 d=await z(t,c);if(d.filter(g=>!g.token).reduce((g,y)=>g+y.satoshis,0n)===0n)throw new Error("the connected wallet has no spendable coins");let u=null;if(!xt(d)){i("preparing-wallet");let g=Et({ownerAddress:h,utxos:d,feeRate:r,addressToLockingBytecode:D}),y=await e.signTransaction(g,{userPrompt:"One-time setup so your wallet can create a TLD certificate"});u=await Pt(t,e,y,i),i("prepared",{txid:u}),d=[{txid:u,vout:0,satoshis:g.transaction.outputs[0].valueSatoshis,address:h,lockingBytecode:D(h)},...d.filter(w=>!w.token&&!g.inputUtxos.some(x=>x.txid===w.txid&&x.vout===w.vout))]}i("building");let f=Ut({tld:l,ownerAddress:h,ownerTokenAddress:j(h),changeAddress:h,records:o,utxos:d,feeAddress:s.address||null,feeSats:BigInt(s.sats??0n),feeRate:r,addressToLockingBytecode:D});i("awaiting-approval");let m=await e.signTransaction(f,{userPrompt:`Register .${l} \u2014 the TLD certificate is minted to your own address`}),p=await Pt(t,e,m,i);return i("registered",{txid:p,category:f.category}),{tld:f.tld,category:f.category,txid:p,prepTxid:u,ownerAddress:h,certificateAddress:j(h),costs:f.costs}}async function Pt(t,e,n,o){let s=n.signedTransactionHash??ue(n.signedTransaction);if(e.walletBroadcasts)return s;o("broadcasting");try{return await tt(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 Oo(t,{session:e,name:n,ownerAddress:o,records:s={},serviceFee:r=L.serviceFee,feeRate:a=L.feeRate,onProgress:i=()=>{}}){i("checking-availability");let l=await $t(t,n);if(!l.available)throw new Error(l.releasePending?`"${l.name}" was just released \u2014 it can be registered once that release is in a block`:`"${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 d=await z(t,c);if(!d.some(p=>!p.token))throw new Error("the connected wallet has no spendable coins");if(!xt(d)){i("preparing-wallet");let p=Et({ownerAddress:h,utxos:d,feeRate:a,addressToLockingBytecode:D}),g=await e.signTransaction(p,{userPrompt:"One-time setup so your wallet can create a name certificate"}),y=await Pt(t,e,g,i);i("prepared",{txid:y}),d=[{txid:y,vout:0,satoshis:p.transaction.outputs[0].valueSatoshis,address:h,lockingBytecode:D(h)},...d.filter(w=>!w.token&&!p.inputUtxos.some(x=>x.txid===w.txid&&x.vout===w.vout))]}i("building");let u=await Mt(t,{name:n,ownerAddress:h,records:s,utxos:d,serviceFee:r,feeRate:a});i("awaiting-approval");let f=await e.signTransaction(u,{userPrompt:`Register ${u.displayName} \u2014 the certificate is minted to your own address`}),m=await Pt(t,e,f,i);return i("registered",{txid:m,category:u.category}),{name:u.name,displayName:u.displayName,category:u.category,txid:m,ownerAddress:h,certificateAddress:j(h),costs:u.costs}}async function _o(t,{addresses:e,category:n,rawName:o}){let s=await z(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 vo(t,{wallet:e,name:n,records:o,feeRate:s=L.feeRate,onProgress:r=()=>{}}){r("resolving");let a=C(n),l=(await yt({client:t})).get(q(a));if(!l)throw new Error(`"${q(a)}" is not registered`);r("loading-coins");let c=await z(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 d=It({name:n,ownerAddress:e.address,ownerTokenAddress:j(e.address),records:o,certificateUtxo:h,utxos:c.filter(m=>!m.token),beaconAddress:L.beacon,feeRate:s,addressToLockingBytecode:D});r("signing");let u=st(d.transaction,d.sourceOutputs,m=>e.keyFor(m));r("broadcasting");let f=await tt(t,u.hex);return r("updated",{txid:f}),{name:d.name,displayName:d.displayName,category:d.category,txid:f,records:o,costs:d.costs}}async function nn(t,e,n=L.beacon){let o=await $e(t,e.txid,!0),s=gt(D(n));return(o?.vout??[]).some(r=>r.scriptPubKey?.hex===s)}async function Ao(t,{wallet:e,name:n,feeRate:o=L.feeRate,onProgress:s=()=>{}}){s("resolving");let r=C(n),i=(await yt({client:t})).get(q(r));if(!i)throw new Error(`"${q(r)}" is not registered`);s("loading-coins");let l=p=>p.token?.category===i.category&&p.token?.nft,c=await z(t,e.watchedAddresses),h=c.find(l);if(!h)throw new Error(`this wallet does not hold the certificate for "${q(r)}" \u2014 only the owner can release it`);let d=null;if(!await nn(t,h)){s("anchoring");let p=It({name:n,ownerAddress:e.address,ownerTokenAddress:j(e.address),records:i.records??{},certificateUtxo:h,utxos:c.filter(y=>!y.token),beaconAddress:L.beacon,feeRate:o,addressToLockingBytecode:D}),g=st(p.transaction,p.sourceOutputs,y=>e.keyFor(y));d=await tt(t,g.hex),s("anchored",{txid:d}),h=null;for(let y=0;y<12&&!h;y++)await new Promise(w=>setTimeout(w,1500)),c=await z(t,e.watchedAddresses),h=c.find(w=>l(w)&&w.txid===d)??null;if(!h)throw new Error("the anchoring update was broadcast but is not visible yet \u2014 try the release again in a minute")}s("building");let u=ae({name:n,ownerAddress:e.address,certificateUtxo:h,utxos:c.filter(p=>!p.token),beaconAddress:L.beacon,feeRate:o,addressToLockingBytecode:D});s("signing");let f=st(u.transaction,u.sourceOutputs,p=>e.keyFor(p));s("broadcasting");let m=await tt(t,f.hex);return s("released",{txid:m}),{name:u.name,displayName:u.displayName,category:u.category,txid:m,anchorTxid:d,costs:u.costs}}async function Bo(t,{session:e,name:n,records:o,feeRate:s=L.feeRate,onProgress:r=()=>{}}){r("resolving");let a=C(n),l=(await yt({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 z(t,c),d=h.find(p=>p.token?.category===l.category&&p.token?.nft);if(!d)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=It({name:n,ownerAddress:d.address,ownerTokenAddress:j(d.address),records:o,certificateUtxo:d,utxos:h.filter(p=>!p.token),beaconAddress:L.beacon,feeRate:s,addressToLockingBytecode:D});r("awaiting-approval");let f=await e.signTransaction(u,{userPrompt:`Point ${u.displayName} somewhere new`}),m=await Pt(t,e,f,r);return r("updated",{txid:m}),{name:u.name,displayName:u.displayName,category:u.category,txid:m,records:o,costs:u.costs}}async function Io(t,{wallet:e,tld:n,records:o,category:s,feeRate:r=L.feeRate,onProgress:a=()=>{}}){if(!s)throw new Error("setTldRecords requires the TLD certificate's category id");a("loading-coins");let i=await z(t,e.watchedAddresses),l=i.find(u=>u.token?.category===s&&u.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=He({tld:n,ownerAddress:e.address,ownerTokenAddress:j(e.address),records:o,certificateUtxo:l,utxos:i.filter(u=>!u.token),feeRate:r,addressToLockingBytecode:D});a("signing");let h=st(c.transaction,c.sourceOutputs,u=>e.keyFor(u));a("broadcasting");let d=await tt(t,h.hex);return a("updated",{txid:d}),{tld:c.tld,displayName:c.displayName,category:c.category,txid:d,records:o,costs:c.costs}}async function Po(t,e){if(!e||e.v!==1&&e.v!==2)throw new Error("manifest.v must be 1 or 2");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(me(n)),s=po.hash(fo(o)),r=t.signMessage(s);return{...e,sig:go(r)}}function me(t){if(t!=null){if(Array.isArray(t))return t.map(me).filter(e=>e!==void 0);if(typeof t=="object"){let e={};for(let n of Object.keys(t).sort()){let o=me(t[n]);o!==void 0&&(e[n]=o)}return e}return t}}async function No(t,e){let n=await z(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:xt(n)}}import{hexToBin as Q,binToHex as nt,encodeDataPush as G,bigIntToVmNumber as Kt,hash256 as ye,hash160 as Ro,encodeLockingBytecodeP2sh32 as Lo,encodeLockingBytecodeP2pkh as an,lockingBytecodeToCashAddress as Do,OpcodesBCH as Co,numberToBinUint32LE as qs,binToNumberUint32LE as sn,secp256k1 as cn,sha256 as Uo,generateSigningSerializationBCH as Fo,encodeTransaction as ln,flattenBinArray as _t}from"@bitauth/libauth";var on={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 $o=2,we=1200,Mo=7200,Ho=t=>{let e=Co[t];if(e===void 0)throw new Error("unknown opcode "+t);return Uint8Array.of(e)};function Ko(t){let e=t.trim().split(/\s+/).filter(Boolean).map(n=>n.startsWith("OP_")?Ho(n):G(Q(n)));return _t(e)}var Wo=Ko(on.bytecode),Ht=t=>G(Kt(BigInt(t))),Go=0,rn=1;function jo(t){let e=Q(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 nt(e.slice(3,23))}function xe({oraclePk:t,sellerPkh:e,targetCents:n,floorSats:o,ceilSats:s,maxAgeSecs:r=we}){if(!(BigInt(n)>0n)||!(BigInt(o)>0n)||BigInt(s)<BigInt(o))throw new Error("bad listing terms");return _t([Ht(r),Ht(s),Ht(o),Ht(n),G(Q(e)),G(Q(t)),Wo])}var Wt=t=>Lo(ye(t));function ke(t,e=O.prefix){let n=Do({bytecode:Wt(t),prefix:e});if(typeof n=="string")throw new Error(n);return n.address}function un({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 dn=t=>({ts:sn(t.slice(0,4)),priceCents:sn(t.slice(4,8)),outpointTxid:nt(t.slice(8,40).slice().reverse())});function hn(t,e,n){return cn.verifySignatureSchnorr(n,t,Uo.hash(e))===!0}var be=(t,e,n,o,{requireGenesis:s=!1}={})=>{let r=F(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(ln(c.transaction).length*n)),d=e+h;if(l<d){let m=F(t,d+200n,{requireGenesis:s});if(m.inputs.length>i.length){r=m;continue}let p=new Error(`not enough funds: need ${d} sat, have ${l} sat`);throw p.needSats=d,p.haveSats=l,p}let u=l-d,f=u>=K;return f||(u=0n),{...o(i,f,u),fee:f?h:l-e,change:u}}throw new Error("could not converge on a fee \u2014 please retry")};function zo({name:t,certificateUtxo:e,utxos:n,sellerAddress:o,oraclePk:s,targetCents:r,floorSats:a,ceilSats:i,maxAgeSecs:l=we,records:c={},beaconAddress:h=at,feeRate:d=1,addressToLockingBytecode:u}){let f=C(t);if(!e?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");let m=u(o),p=jo(nt(u(e.address||o))),g=xe({oraclePk:s,sellerPkh:p,targetCents:r,floorSats:a,ceilSats:i,maxAgeSecs:l}),y=Wt(g),w=J("UPD",f,c),x=n.filter(k=>!k.token),v=R+A-BigInt(e.satoshis);return{...be(x,v>0n?v:0n,d,(k,B,T)=>({transaction:{version:2,locktime:0,inputs:[rt(e),...k.map(S=>rt(S))],outputs:[{lockingBytecode:y,valueSatoshis:R,token:lt(e.token)},{lockingBytecode:et(w),valueSatoshis:0n},{lockingBytecode:u(h),valueSatoshis:A},...B?[{lockingBytecode:m,valueSatoshis:T}]:[]]},sourceOutputs:[ut(e),...k.map(S=>ut(S))]})),name:f,redeem:g,redeemHex:nt(g),address:ke(g,o.split(":")[0]),sellerPkh:p,covenantVout:0}}function pn(t){let e=Q(t.redeem_hex);return{redeem:e,utxo:{txid:t.outpoint.txid,vout:t.outpoint.vout,satoshis:BigInt(t.outpoint.satoshis??R),lockingBytecode:Wt(e),token:t.token}}}function qo({listing:t,quote:e,buyerAddress:n,buyerTokenAddress:o,utxos:s,records:r={},beaconAddress:a=at,feeRate:i=1,addressToLockingBytecode:l}){let c=C(t.name),h=Q(e.message),d=Q(e.signature);if(!hn(Q(t.oracle_pk),h,d))throw new Error("oracle signature does not verify against the listing's oracle key");let{ts:u,priceCents:f,outpointTxid:m}=dn(h);if(m!==String(t.outpoint.txid).toLowerCase())throw new Error("quote was issued for a different listing");let p=un({targetCents:t.target_cents,priceCents:f,floorSats:t.floor_sats,ceilSats:t.ceil_sats}),{redeem:g,utxo:y}=pn(t),w=an(Q(t.seller_pkh)),x=_t([G(d),G(h),G(Kt(BigInt(Go))),G(g)]),v=l(n),b=l(o??n),k=J("UPD",c,r),B=s.filter(P=>!P.token),T=p+R+A-y.satoshis;return{...be(B,T,i,(P,I,E)=>({transaction:{version:2,locktime:Math.max(0,u-Mo),inputs:[rt(y,x),...P.map(_=>rt(_))],outputs:[{lockingBytecode:w,valueSatoshis:p},{lockingBytecode:b,valueSatoshis:R,token:lt(y.token)},{lockingBytecode:et(k),valueSatoshis:0n},{lockingBytecode:l(a),valueSatoshis:A},...I?[{lockingBytecode:v,valueSatoshis:E}]:[]]},sourceOutputs:[ut(y),...P.map(_=>ut(_))]})),name:c,covenantInputIndex:0,priceSats:p,priceCents:f,quoteTs:u}}function Yo({listing:t,sellerAddress:e,sellerTokenAddress:n,utxos:o,records:s={},beaconAddress:r=at,feeRate:a=1,addressToLockingBytecode:i,keyFor:l}){let c=C(t.name),{redeem:h,utxo:d}=pn(t),u=an(Q(t.seller_pkh)),f=l(nt(u));if(!f)throw new Error("this wallet does not hold the seller key for this listing");let m=f.privateKey,p=f.publicKey,g=i(n??e),y=J("UPD",c,s),w=o.filter(_=>!_.token),x=R+A-d.satoshis,v=_t([G(new Uint8Array(65)),G(p),G(Kt(BigInt(rn))),G(h)]),b=be(w,x>0n?x:0n,a,(_,U,N)=>({transaction:{version:2,locktime:0,inputs:[rt(d,v),..._.map(M=>rt(M))],outputs:[{lockingBytecode:g,valueSatoshis:R,token:lt(d.token)},{lockingBytecode:et(y),valueSatoshis:0n},{lockingBytecode:i(r),valueSatoshis:A},...U?[{lockingBytecode:i(e),valueSatoshis:N}]:[]]},sourceOutputs:[ut(d),..._.map(M=>ut(M))]})),k=Ot(b.transaction,b.sourceOutputs,l,{skip:[0]}),B=Fo({inputIndex:0,sourceOutputs:b.sourceOutputs,transaction:k.transaction},{coveredBytecode:h,signingSerializationType:Uint8Array.of(Ft)}),T=cn.signMessageHashSchnorr(m,ye(B));if(typeof T=="string")throw new Error(T);let S=_t([T,Uint8Array.of(Ft)]),P=_t([G(S),G(p),G(Kt(BigInt(rn))),G(h)]),I={...k.transaction,inputs:k.transaction.inputs.map((_,U)=>U===0?{..._,unlockingBytecode:P}:_)},E=ln(I);return{name:c,transaction:I,sourceOutputs:b.sourceOutputs,hex:nt(E),txid:nt(ye(E).slice().reverse())}}function Vo(t,{oraclePk:e}={}){let n=o=>({ok:!1,error:o});try{if(t?.kind!=="usd"||t.v!==$o)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=xe({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(nt(o)!==t.redeem_hex)return n("redeem script does not match the stated terms");let s=String(t.seller).split(":")[0]||O.prefix;return ke(o,s)!==t.covenant_address?n("covenant address does not match"):nt(Ro(Q(t.seller_pkh))).length!==40?n("bad seller pkh"):t.token?.category!==t.category||!t.token?.nft?n("token does not match category"):Q(t.token.nft.commitment||"").length===0||nt(new TextEncoder().encode(C(t.name)))!==t.token.nft.commitment?n("commitment does not match the name"):{ok:!0,name:C(t.name),covenant_lock:nt(Wt(o))}}catch(o){return n(String(o?.message||o))}}import{hash160 as Xo,lockingBytecodeToCashAddress as Jo,binToHex as tr}from"@bitauth/libauth";function fn(t){return Uint8Array.from([118,169,20,...Xo(t),136,172])}function Qo(t,e=O.prefix,n=!1){let o=Jo({bytecode:fn(t),prefix:e,tokenSupport:n});if(typeof o=="string")throw new Error(`address encoding failed: ${o}`);return o.address}function Zo(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 mr,hexToBin as yr}from"@bitauth/libauth";import{stringify as xr}from"@bitauth/libauth";export{Jt as BuiltInWallet,Hn as CHIPNET_PREFIX,we as DEFAULT_MAX_AGE_SECS,Ee as DEFAULT_NETWORK_ID,At as DEFAULT_PREFIX,X as InsufficientFundsError,Kn as MAINNET_PREFIX,O as NETWORK,St as NETWORKS,Ct as NoGenesisInputError,L as REGISTRAR,oe as TLD_BEACON,D as addressToLockingBytecode,Vn as addressToScripthash,mr as binToHex,tt as broadcast,ko as buildCosignRequest,yt as buildIndex,io as buildListing,Et as buildPrepTx,ie as buildRegistrationTx,ae as buildReleaseTx,Ut as buildTldRegistrationTx,It as buildUpdateTx,qo as buildUsdBuyTx,Yo as buildUsdCancelTx,zo as buildUsdListingTx,$t as checkAvailability,lo as completeSale,xo as connect,Zo as describeGenesisRequirement,q as displayName,_o as findCertificateUtxo,tn as findTldCertificateUtxo,Qe as findTldOwnerAddress,No as getBalance,Rt as getNetwork,Fe as getUtxos,z as getUtxosForAddresses,xt as hasGenesisInput,yr as hexToBin,nn as isAnchored,C as normalizeName,Tt as normalizeTld,dn as parseOracleMessage,se as payloadBudget,un as payoutSats,so as priceSummary,Qo as pubkeyToAddress,fn as pubkeyToLockingBytecode,Mt as quoteRegistration,To as registerTldWithBuiltInWallet,Eo as registerTldWithExternalWallet,So as registerWithBuiltInWallet,Oo as registerWithExternalWallet,Ao as releaseWithBuiltInWallet,jt as requireBeacons,Ln as resolveName,vo as setRecordsWithBuiltInWallet,Bo as setRecordsWithExternalWallet,Io as setTldRecordsWithBuiltInWallet,bo as signCosignRequest,Ot as signInputs,Po as signRecordsManifest,st as signTransaction,ge as sourceOutputFromJson,fe as sourceOutputToJson,Ze as splitServiceFee,xr as stringify,j as toTokenAddress,Ke as toWcTransactionObject,le as txidOf,ue as txidOfHex,ke as usdListingAddress,xe as usdListingRedeem,Xe as verifyListing,hn as verifyOracleMessage,Vo as verifyUsdListing};
|