Rebuilt so the dashboard and market index names by the same rule as the gateway and the clients.
7 lines
70 KiB
JavaScript
7 lines
70 KiB
JavaScript
import{generateBip39Mnemonic as Zn,deriveSeedFromBip39Mnemonic as We,deriveHdPrivateNodeFromSeed as to,deriveHdPath as eo,secp256k1 as Ge,hash160 as no,encodeCashAddress as Bs,lockingBytecodeToCashAddress as oo,cashAddressToLockingBytecode as Is,binToHex as so,hexToBin as Ps,utf8ToBin as ze,binToBase64 as te,base64ToBin as ee}from"@bitauth/libauth";var Tt={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,blocklists:[{name:"sirius-blocklist.x",beacon:"bchtest:qrrnwvuasq5fy63mdvp3umx5qfavtu7mnq950rdssw",scripthash:"fa14c5fd7a22bd1856b44168823a1ab3ff50961c917dafbcba749aeaa7b26646"}]},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,blocklists:[]}},Le="chipnet";function Pn(){let t=typeof globalThis<"u"?globalThis.BNS_NETWORK:null,e=typeof process<"u"&&process.env?process.env.BNS_NETWORK:null;return String(t||e||Le).trim().toLowerCase()}function Et(t){if(t&&typeof t=="object")return t;let e=t||Pn(),n=Tt[e];if(!n)throw new Error(`unknown network "${e}" (known: ${Object.keys(Tt).join(", ")})`);return n}var E=Et();function zt(t=E){let e=Et(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 ws=E.beacon,xs=E.beaconScripthash,bs=E.tldBeacon,ks=E.tldBeaconScripthash,Ss=E.electrum,Ts=Tt.chipnet.electrum,Es=E.electrumListName,Ae="BNS1";var De="bch",Nn=/^[a-z0-9-]{1,32}$/,Ce=/^[a-z0-9-]{1,16}$/,Ue=/^[a-z0-9-]{1,32}(\.[a-z0-9-]{1,16})?$/;function Fe(t){return t.includes(".")?t:t+"."+De}var $e=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},Yt=t=>[...new TextEncoder().encode(t)].map(e=>e.toString(16).padStart(2,"0")).join("");function Rn(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=De):(s=n[n.length-1],o=n[n.length-2]),!Nn.test(o)||!Ce.test(s))throw new Error(`invalid name "${t}" (allowed: <label>.<tld>, [a-z0-9-])`);return`${o}.${s}`}var Lt=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{}}},Ln=t=>typeof t=="string"?{url:t}:t;async function Dt(t,e,{directIP:n=!1}={}){let o;for(let s of t){let r=Ln(s);try{return await new Lt(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 Lt(i,e,{servername:a.hostname}).connect()}catch(a){o=a}}throw o??new Error("no electrum server reachable")}function Dn(t){if(!t||!t.startsWith("6a"))return null;let e=$e(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(Ae))return null;try{let r=JSON.parse(s.slice(Ae.length));if(!Cn.has(r.o))return null;if(typeof r.n=="string"||r.o==="RPT"&&Array.isArray(r.n)&&r.n.every(a=>typeof a=="string"))return r}catch{}return null}function Vt(t){let e=null;for(let n of t||[]){let o=Dn(n&&n.scriptPubKey?n.scriptPubKey.hex:null);if(o){if(e)return null;e=o}}return e}var Cn=new Set(["REG","UPD","REL","TREG","TUPD","RPT","BLK","UBK"]);function Xt(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 Jt(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 Me(t,e){let n=e&&e.tokenData;if(!n||!n.nft||typeof n.category!="string")return!1;let o=n.category;if(!(t.vin||[]).some(a=>a&&a.txid===o&&a.vout===0)||(t.vout||[]).filter(a=>a.tokenData&&a.tokenData.category===o).length!==1)return!1;let s=n.nft.capability;if(s!=null&&s!==""&&s!=="none")return!1;let r;try{r=BigInt(n.amount??0)}catch{return!1}return r===0n}function qt(t){let e=t.lastIndexOf(".");return e<0?t:t.slice(e+1)}function Un(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=E){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(Xt);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 Jt(o.filter(l=>s.has(l.tx_hash)),s)){let l=s.get(a),c=l.vout||[],h=Vt(c);if(!h||typeof h.n!="string"||!Ce.test(h.n))continue;let d=h.n;if(h.o==="TREG"){if(r.has(d))continue;let u=Yt(d),f=c.find(y=>y.tokenData?.nft&&y.tokenData.nft.commitment===u);if(!f||!Me(l,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 Fn(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 $n(t,e){let n=Fn(t,e);return n.policy==="cosign"||n.hidden===1||n.hidden===!0||n.hidden==="1"}function Mn(t,e,n){let o=Yt(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}function He(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 Hn(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=He(o,n);return!!(s&&s.tokenData&&s.tokenData.nft&&s.tokenData.category===e.category)})}function Kn(t,e){return t===void 0?!0:t>0?!(e>0)||e>t:!1}async function pt({network:t=E,electrum:e=Et(t).electrum,WebSocket:n,client:o,directIP:s=!1,enforceTld:r=!1,cosignGate:a=!0}={}){let i=zt(t),l=o??await Dt(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(Xt);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,y=new Map;for(let{tx_hash:p,height:m}of Jt(d.filter(g=>u.has(g.tx_hash)),u)){let g=u.get(p),w=g.vout||[],x=Vt(w);if(!x)continue;let v=x.n;if(!Ue.test(v))continue;let k=Fe(v);if(x.o==="REG"){if(f.has(k)||!Kn(y.get(k),m)||r&&!Un(qt(k),m,c))continue;if(a&&c){let T=c.get(qt(k));if(T&&$n(T,m)&&!Mn(w,T,qt(k)))continue}let b=Yt(v),A=w.find(T=>T.tokenData?.nft&&T.tokenData.nft.commitment===b);if(!A||!Me(g,A))continue;f.set(k,{name:k,category:A.tokenData.category,records:x.r??{},txid:p,height:m,updatedTxid:null,owner:Be(A)}),y.delete(k)}else if(x.o==="REL"){let b=f.get(k);if(!b||!Hn(g,b,u))continue;f.delete(k),y.set(k,m)}else if(x.o==="UPD"){let b=f.get(k);if(!b)continue;let A=w.find(T=>T.tokenData&&T.tokenData.category===b.category);if(!A)continue;b.records=x.r??{},b.updatedTxid=p,b.owner=Be(A)??b.owner}}return h&&Object.defineProperty(f,"integrity",{value:h,enumerable:!1}),Object.defineProperty(f,"released",{value:y,enumerable:!1}),f}finally{o||l.close()}}var Wn=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),ot=(t,e)=>t>>>e|t<<32-e;function Gn(t){let e=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),n=t.length,o=new Uint8Array(n+9+63>>6<<6);o.set(t),o[n]=128;let s=new DataView(o.buffer);s.setUint32(o.length-8,Math.floor(n*8/4294967296)),s.setUint32(o.length-4,n*8>>>0);let r=new Uint32Array(64);for(let l=0;l<o.length;l+=64){for(let g=0;g<16;g++)r[g]=s.getUint32(l+g*4);for(let g=16;g<64;g++){let w=ot(r[g-15],7)^ot(r[g-15],18)^r[g-15]>>>3,x=ot(r[g-2],17)^ot(r[g-2],19)^r[g-2]>>>10;r[g]=r[g-16]+w+r[g-7]+x|0}let c=e[0],h=e[1],d=e[2],u=e[3],f=e[4],y=e[5],p=e[6],m=e[7];for(let g=0;g<64;g++){let w=m+(ot(f,6)^ot(f,11)^ot(f,25))+(f&y^~f&p)+Wn[g]+r[g]|0,x=(ot(c,2)^ot(c,13)^ot(c,22))+(c&h^c&d^h&d)|0;m=p,p=y,y=f,f=u+w|0,u=d,d=h,h=c,c=w+x|0}e[0]+=c,e[1]+=h,e[2]+=d,e[3]+=u,e[4]+=f,e[5]+=y,e[6]+=p,e[7]+=m}let a=new Uint8Array(32),i=new DataView(a.buffer);for(let l=0;l<8;l++)i.setUint32(l*4,e[l]);return a}var Ke=t=>[...t].map(e=>e.toString(16).padStart(2,"0")).join(""),jn="qpzry9x8gf2tvdw0s3jn54khce6mua7l";function qn(t){let e=[0x98f2bc8e61n,0x79b76d99e2n,0xf33e5fb3c4n,0xae2eabe2a8n,0x1e4f43e470n],n=1n;for(let o of t){let s=n>>35n;n=(n&0x07ffffffffn)<<5n^BigInt(o);for(let r=0;r<5;r++)s>>BigInt(r)&1n&&(n^=e[r])}return n^1n}function Zt(t){let e=String(t).trim().toLowerCase(),n=e.indexOf(":");if(n<1)throw new Error(`address needs its network prefix: "${t}"`);let o=e.slice(0,n),s=[...e.slice(n+1)].map(u=>jn.indexOf(u));if(s.length<9||s.some(u=>u<0))throw new Error(`not a cashaddr: "${t}"`);if(qn([...[...o].map(u=>u.charCodeAt(0)&31),0,...s])!==0n)throw new Error(`bad cashaddr checksum: "${t}"`);let r=[],a=0,i=0;for(let u of s.slice(0,-8))for(a=a<<5|u,i+=5;i>=8;)i-=8,r.push(a>>i&255);let l=r[0],c=l>>3&15,h=Ke(r.slice(1)),d=[20,24,28,32,40,48,56,64][l&7];if(h.length!==d*2)throw new Error(`cashaddr hash length mismatch: "${t}"`);if((c===0||c===2)&&d===20)return"76a914"+h+"88ac";if((c===1||c===3)&&d===20)return"a914"+h+"87";if((c===1||c===3)&&d===32)return"aa20"+h+"87";throw new Error(`unsupported address type: "${t}"`)}function zn(t){return Ke(Gn($e(Zt(t))).reverse())}var Ie=new Set(["phishing","impersonation","malware","scam-financial","csam","stolen"]);function Pe(t,e,n){return(t.vin||[]).some(o=>{let s=He(o,n);return!!(s&&s.scriptPubKey&&s.scriptPubKey.hex===e)})}var Yn=t=>typeof t=="string"&&/^[0-9a-f]{64}$/.test(t);function Ne(t){return typeof t=="string"&&Ue.test(t)?Fe(t):null}function Vn({history:t,txs:e,address:n,source:o=null}){let s=Zt(n),r=e instanceof Map?e:new Map(Object.entries(e||{})),a=Jt([...t||[]].filter(h=>r.has(h.tx_hash)).sort(Xt),r),i=h=>Vt(h.vout),l=new Map;for(let{tx_hash:h,height:d}of a){let u=r.get(h),f=i(u);if(!f||f.o!=="RPT"||!Pe(u,s,r)||f.t!=="block"&&f.t!=="unblock")continue;let y=(f.n||[]).map(Ne);!y.length||y.some(p=>!p)||f.t==="block"&&!Ie.has(f.r)||l.set(h,{type:f.t,names:new Set(y),reason:f.r??null,evidence:f.e??null,vote:f.v??null,height:d})}let c=new Map;for(let{tx_hash:h,height:d}of a){let u=r.get(h),f=i(u);if(!f||f.o!=="BLK"&&f.o!=="UBK"||!Pe(u,s,r))continue;let y=Ne(f.n);if(!y||!Yn(f.p))continue;let p=l.get(f.p);if(!(!p||!p.names.has(y)))if(f.o==="BLK"){if(p.type!=="block"||!Ie.has(f.r)||p.reason!==f.r)continue;c.set(y,{name:y,reason:f.r,reportTxid:f.p,txid:h,height:d,evidence:f.e??p.evidence,vote:p.vote,source:o,address:n})}else{if(p.type!=="unblock")continue;c.delete(y)}}return c}function Re(t,e){let n=t&&t.name&&e&&typeof e.get=="function"?e.get(t.name)?.records?.bl:null;if(typeof n=="string")try{return Zt(n),n}catch{}return t?.beacon??null}async function Xn({network:t=E,lists:e,index:n=null,electrum:o,WebSocket:s,client:r,directIP:a=!1}={}){let i=Et(t),l=e??i.blocklists??[],c=new Map;if(!l.length)return c;let h=o??i.electrum.filter(u=>!i.beaconOnly.test(typeof u=="string"?u:u.url)),d=r;if(!d)try{d=await Dt(h,s,{directIP:a})}catch(u){let f=new Set((i.blocklists||[]).map(y=>y.beacon));if(o||!l.every(y=>f.has(Re(y,n))))throw u;d=await Dt(i.electrum,s,{directIP:a})}try{for(let u of l){let f=Re(u,n);if(!f)continue;let y=zn(f),p=typeof d.unionHistory=="function"?(await d.unionHistory(y)).history:await d.call("blockchain.scripthash.get_history",[y]);if(!p||!p.length)continue;let m=new Map;for(let{tx_hash:g}of p)try{m.set(g,await d.call("blockchain.transaction.get",[g,!0]))}catch{}for(let[g,w]of Vn({history:p,txs:m,address:f,source:u.name??f})){let x=c.get(g);x?x.sources.push(w):c.set(g,{...w,sources:[w]})}}return c}finally{r||d.close()}}function Jn(t,e){let n=t&&e&&typeof e.get=="function"?e.get(t.name):null;return n?{...t,blocked:!0,blockReason:n.reason,blockReportTxid:n.reportTxid,blockedBy:n.source}:t}async function Qn(t,e={}){let n=Rn(t),o=Et(e.network),s=e.blocklists===void 0?o.blocklists??[]:e.blocklists||[];if(!s.length)return(await pt(e)).get(n)??null;let r=e.client??await Dt(e.electrum??o.electrum,e.WebSocket,{directIP:!!e.directIP});try{let a=await pt({...e,client:r}),i=a.get(n)??null;if(!i)return null;let l=null;try{l=await Xn(e.client?{network:o,lists:s,index:a,client:e.client}:{network:o,lists:s,index:a,WebSocket:e.WebSocket,directIP:!!e.directIP})}catch{}return Jn(i,l)}finally{e.client||r.close()}}var Os=E.rootTldName,_s=E.bootstrapTlds.slice();var ro="bchtest",io="bitcoincash",It=E.prefix,ne="m/44'/145'/0'",ao=5,Ct="bns.wallet.v1";function Ye(t){let e=no(t);return Uint8Array.from([118,169,20,...e,136,172])}function je(t,e,n){let o=oo({bytecode:Ye(t),prefix:e,tokenSupport:n});if(typeof o=="string")throw new Error(`address encoding failed: ${o}`);return o.address}var oe=class t{constructor(e,n,o=It,s=ne){this.mnemonic=e,this.prefix=o,this.accountPath=s,this._root=to(n),this._keys=new Map,this._derive()}static async create(e=It,n=ne){let o=Zn();return new t(o,await We(o),e,n)}static async fromMnemonic(e,n=It,o=ne){let s=String(e).trim().toLowerCase().replace(/\s+/g," "),r=await We(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<ao;o++){let s=`${this.accountPath}/${e}/${o}`,r=eo(this._root,s);if(typeof r=="string")throw new Error(`HD derivation failed at ${s}: ${r}`);let a=Ge.derivePublicKeyCompressed(r.privateKey);if(typeof a=="string")throw new Error(`pubkey derivation failed: ${a}`);let i=Ye(a),l={path:s,branch:e,index:o,privateKey:r.privateKey,publicKey:a,lockingBytecode:i,address:je(a,this.prefix,!1),tokenAddress:je(a,this.prefix,!0)};n.push(l),this._keys.set(so(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=Ge.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 qe(e,n),r=new Uint8Array(await crypto.subtle.encrypt({name:"AES-GCM",iv:o},s,ze(this.mnemonic)));return JSON.stringify({v:1,kdf:"PBKDF2-SHA256",iterations:se,prefix:this.prefix,salt:te(n),iv:te(o),ct:te(r)})}static async decrypt(e,n){let o=typeof e=="string"?JSON.parse(e):e,s=await qe(n,ee(o.salt),o.iterations??se),r;try{r=await crypto.subtle.decrypt({name:"AES-GCM",iv:ee(o.iv)},s,ee(o.ct))}catch{throw new Error("wrong password")}return t.fromMnemonic(new TextDecoder().decode(r),o.prefix??It)}async save(e,n=globalThis.localStorage){n.setItem(Ct,await this.encrypt(e))}static async load(e,n=globalThis.localStorage){let o=n.getItem(Ct);return o?t.decrypt(o,e):null}static exists(e=globalThis.localStorage){return!!e?.getItem(Ct)}static forget(e=globalThis.localStorage){e.removeItem(Ct)}},se=25e4;async function qe(t,e,n=se){let o=await crypto.subtle.importKey("raw",ze(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 Ds=Tt.chipnet.electrum.map(t=>t.url),Ut=E.electrum.map(t=>t.url),re=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 Ve(t=Ut,e){let n=[];for(let o of t)try{return await new re(o,e).connect()}catch(s){n.push(`${o}: ${s?.message??s}`)}throw co(t.length,n)}function co(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 lo,lockingBytecodeToCashAddress as uo,sha256 as fo,hash160 as Fs,binToHex as ho,hexToBin as $s}from"@bitauth/libauth";function Xe(t){return ho(fo.hash(t).slice().reverse())}function D(t){let e=lo(t);if(typeof e=="string")throw new Error(`bad address "${t}": ${e}`);return e.bytecode}function po(t){return Xe(D(t))}function j(t){let e=D(t),n=String(t).includes(":")?t.split(":")[0]:E.prefix,o=uo({bytecode:e,prefix:n,tokenSupport:!0});if(typeof o=="string")throw new Error(`cannot token-encode "${t}": ${o}`);return o.address}async function Je(t,e){let n=D(e),o=Xe(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 q(t,e){let n=[];for(let o of e)n.push(...await Je(t,o));return n}async function tt(t,e){return t.call("blockchain.transaction.broadcast",[e])}async function Qe(t,e,n=!0){return t.call("blockchain.transaction.get",[e,n])}import{binToHex as Pt,hexToBin as V,utf8ToBin as gt,binToUtf8 as ce,encodeTransaction as go,decodeTransaction as Ws}from"@bitauth/libauth";var yo="BNS1",ct=E.beacon,le=E.tldBeacon,B=600n,R=1000n,K=546n,ie="bch",ae=200,mo=/^[a-z0-9-]{1,32}$/,Ze=/^[a-z0-9-]{1,16}$/;function Ot(t){let e=String(t).toLowerCase().trim().replace(/^\.+/,"").replace(/\.+$/,"");if(!Ze.test(e))throw new Error(`invalid TLD "${t}" (allowed: [a-z0-9-]{1,16})`);return e}var Ft=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=ie):(o=e[e.length-1],n=e[e.length-2]),!mo.test(n)||!Ze.test(o))throw new Error(`invalid name "${t}" (allowed: <label>.<tld>, [a-z0-9-])`);return o===ie?n:`${n}.${o}`}function z(t){return t.includes(".")?t:`${t}.${ie}`}function J(t,e,n){let o=JSON.stringify({o:t,n:e,r:n??{}}),s=gt(yo+o);if(s.length>ae)throw new Error(`records too large (${s.length} > ${ae} bytes)`);return s}function ue(t,e="REG"){return ae-J(e,t,{}).length}function wo(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,...wo(t)])}function de(){return Uint8Array.from([65,...new Uint8Array(65),33,...new Uint8Array(33)])}var xo=t=>!t.token;function F(t,e,{requireGenesis:n=!0}={}){let o=t.filter(xo),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 Ft("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 yt(t){return{outpointTransactionHash:V(t.txid),outpointIndex:t.vout,sequenceNumber:4294967294,unlockingBytecode:de()}}function xt(t){return{...yt(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 st(t){return go(t).length}function fe({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=ct,feeRate:d=1,addressToLockingBytecode:u,cosignUtxo:f=null,cosignTokenAddress:y=null}){if(typeof u!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let p=C(t),m=J("REG",p,s),g=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(y??n??e):null;if(g>0n&&!a)throw new Error("feeSats set but feeAddress missing");if(w>0n&&!l)throw new Error("tldFeeSats set but tldFeeAddress missing");let k=u(o??e),b=u(n??e),A=u(h),T=g>0n?u(a):null,S=w>0n?u(l):null,P=R+B+g+w+x,I=F(r,P+300n-x),O=0n,_=0n,U=!0;for(let N=0;N<6;N++){let{inputs:M}=I,H=f?[...M,f]:M,W=I.totalSats+x,ft=H[0],at=V(ft.txid),Y=(kt,St)=>{let Z=[];return kt&&Z.push({lockingBytecode:k,valueSatoshis:St}),Z.push({lockingBytecode:b,valueSatoshis:R,token:{amount:0n,category:at,nft:{capability:"none",commitment:gt(p)}}}),Z.push({lockingBytecode:et(m),valueSatoshis:0n}),Z.push({lockingBytecode:A,valueSatoshis:B}),S&&Z.push({lockingBytecode:S,valueSatoshis:w}),T&&Z.push({lockingBytecode:T,valueSatoshis:g}),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(yt),outputs:Z}},An=Y(!0,1000000n),Bn=st(An);O=BigInt(Math.ceil(Bn*d));let Bt=P+O;if(W<Bt){let kt=F(r,Bt+200n-x);if(kt.inputs.length>M.length){I=kt;continue}throw new X(`not enough funds: need ${Bt} sat, have ${W} sat`,{needSats:Bt,haveSats:W})}if(_=W-Bt,U=_>=K,!U){let kt=Y(!1,0n);O=W-P;let St=BigInt(Math.ceil(st(kt)*d));if(O<St){let Z=F(r,P+St+K+200n-x);if(Z.inputs.length>M.length){I=Z;continue}throw new X(`not enough funds: need ${P+St} sat, have ${W} sat`,{needSats:P+St,haveSats:W})}_=0n}let In=Y(U,_),ht={},wt=0;return U&&(ht.change=wt++),ht.certificate=wt++,ht.opReturn=wt++,ht.beacon=wt++,S&&(ht.tldOwnerFee=wt++),T&&(ht.serviceFee=wt++),f&&(ht.cosignCertificate=wt++),{name:p,displayName:z(p),category:Pt(at),transaction:In,sourceOutputs:H.map(xt),inputUtxos:H,outputMap:ht,payload:m,costs:{certificateDustSats:R,beaconDustSats:B,serviceFeeSats:g,tldOwnerFeeSats:w,chainFeeSats:O,changeSats:_,totalInputSats:W,netCostSats:g+w+O+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function $t({tld:t,ownerAddress:e,ownerTokenAddress:n,changeAddress:o,records:s={},utxos:r,feeAddress:a=null,feeSats:i=0n,beaconAddress:l=le,feeRate:c=1,addressToLockingBytecode:h}){if(typeof h!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let d=Ot(t),u=J("TREG",d,s),f=BigInt(i??0n);if(f>0n&&!a)throw new Error("feeSats set but feeAddress missing");let y=h(o??e),p=h(n??e),m=h(l),g=f>0n?h(a):null,w=R+B+f,x=F(r,w+300n),v=0n,k=0n,b=!0;for(let A=0;A<6;A++){let{inputs:T,totalSats:S}=x,P=T[0],I=V(P.txid),O=(ft,at)=>{let Y=[];return ft&&Y.push({lockingBytecode:y,valueSatoshis:at}),Y.push({lockingBytecode:p,valueSatoshis:R,token:{amount:0n,category:I,nft:{capability:"none",commitment:gt(d)}}}),Y.push({lockingBytecode:et(u),valueSatoshis:0n}),Y.push({lockingBytecode:m,valueSatoshis:B}),g&&Y.push({lockingBytecode:g,valueSatoshis:f}),{version:2,locktime:0,inputs:T.map(yt),outputs:Y}},_=O(!0,1000000n),U=st(_);v=BigInt(Math.ceil(U*c));let N=w+v;if(S<N){let ft=F(r,N+200n);if(ft.inputs.length>T.length){x=ft;continue}throw new X(`not enough funds: need ${N} sat, have ${S} sat`,{needSats:N,haveSats:S})}if(k=S-N,b=k>=K,!b){let ft=O(!1,0n);v=S-w;let at=BigInt(Math.ceil(st(ft)*c));if(v<at){let Y=F(r,w+at+K+200n);if(Y.inputs.length>T.length){x=Y;continue}throw new X(`not enough funds: need ${w+at} sat, have ${S} sat`,{needSats:w+at,haveSats:S})}k=0n}let M=O(b,k),H={},W=0;return b&&(H.change=W++),H.certificate=W++,H.opReturn=W++,H.beacon=W++,g&&(H.serviceFee=W++),{tld:d,category:Pt(I),transaction:M,sourceOutputs:T.map(xt),inputUtxos:T,outputMap:H,payload:u,costs:{certificateDustSats:R,beaconDustSats:B,serviceFeeSats:f,chainFeeSats:v,changeSats:k,totalInputSats:S,netCostSats:f+v+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function Nt({name:t,ownerAddress:e,ownerTokenAddress:n,records:o={},certificateUtxo:s,utxos:r,beaconAddress:a=ct,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=Pt(gt(c));if(s.token.nft.commitment!==h)throw new Error(`certificate commitment mismatch: holds "${ce(V(s.token.nft.commitment))}", asked to update "${c}"`);let d=J("UPD",c,o),u=l(e),f=l(n??e),y=l(a),p=R+B,m=F(r,p+400n,{requireGenesis:!1}),g=0n,w=0n,x=!0;for(let v=0;v<6;v++){let k=[s,...m.inputs],b=s.satoshis+m.totalSats,A=(_,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:gt(c)}}}),N.push({lockingBytecode:et(d),valueSatoshis:0n}),N.push({lockingBytecode:y,valueSatoshis:B}),{version:2,locktime:0,inputs:k.map(yt),outputs:N}},T=st(A(!0,1000000n));g=BigInt(Math.ceil(T*i));let S=p+g;if(b<S){let _=F(r,S+200n,{requireGenesis:!1});if(_.inputs.length>m.inputs.length){m=_;continue}throw new X(`not enough funds: need ${S} sat, have ${b} sat`,{needSats:S,haveSats:b})}w=b-S,x=w>=K,x||(g=b-p,w=0n);let P=A(x,w),I={},O=0;return x&&(I.change=O++),I.certificate=O++,I.opReturn=O++,I.beacon=O++,{name:c,displayName:z(c),category:s.token.category,transaction:P,sourceOutputs:k.map(xt),inputUtxos:k,outputMap:I,payload:d,costs:{certificateDustSats:R,beaconDustSats:B,serviceFeeSats:0n,chainFeeSats:g,changeSats:w,totalInputSats:b,netCostSats:g+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function he({name:t,ownerAddress:e,certificateUtxo:n,utxos:o=[],beaconAddress:s=ct,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=Pt(gt(i));if(n.token.nft.commitment!==l)throw new Error(`certificate commitment mismatch: holds "${ce(V(n.token.nft.commitment))}", asked to release "${i}"`);let c=J("REL",i,{}),h=a(e),d=a(s),u=B,f={inputs:[],totalSats:0n},y=0n,p=0n,m=!0;for(let g=0;g<6;g++){let w=[n,...f.inputs],x=n.satoshis+f.totalSats,v=(P,I)=>{let O=[];return P&&O.push({lockingBytecode:h,valueSatoshis:I}),O.push({lockingBytecode:et(c),valueSatoshis:0n}),O.push({lockingBytecode:d,valueSatoshis:B}),{version:2,locktime:0,inputs:w.map(yt),outputs:O}},k=BigInt(Math.ceil(st(v(!1,0n))*r)),b=BigInt(Math.ceil(st(v(!0,1000000n))*r));if(x<u+k){let P=F(o,u+b+200n,{requireGenesis:!1});if(P.inputs.length>f.inputs.length){f=P;continue}throw new X(`not enough funds: need ${u+k} sat, have ${x} sat`,{needSats:u+k,haveSats:x})}p=x-u-b,m=p>=K,m?y=b:(y=x-u,p=0n);let A=v(m,p),T={},S=0;return m&&(T.change=S++),T.opReturn=S++,T.beacon=S++,{name:i,displayName:z(i),category:n.token.category,transaction:A,sourceOutputs:w.map(xt),inputUtxos:w,outputMap:T,payload:c,costs:{beaconDustSats:B,chainFeeSats:y,changeSats:p,totalInputSats:x,netCostSats:y+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function tn({tld:t,ownerAddress:e,ownerTokenAddress:n,records:o={},certificateUtxo:s,utxos:r,beaconAddress:a=le,feeRate:i=1,addressToLockingBytecode:l}){if(typeof l!="function")throw new Error("addressToLockingBytecode must be injected (see chain.js)");let c=Ot(t);if(!s?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");let h=Pt(gt(c));if(s.token.nft.commitment!==h)throw new Error(`TLD certificate commitment mismatch: holds "${ce(V(s.token.nft.commitment))}", asked to update ".${c}"`);let d=J("TUPD",c,o),u=l(e),f=l(n??e),y=l(a),p=R+B,m=F(r,p+400n,{requireGenesis:!1}),g=0n,w=0n,x=!0;for(let v=0;v<6;v++){let k=[s,...m.inputs],b=s.satoshis+m.totalSats,A=(_,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:gt(c)}}}),N.push({lockingBytecode:et(d),valueSatoshis:0n}),N.push({lockingBytecode:y,valueSatoshis:B}),{version:2,locktime:0,inputs:k.map(yt),outputs:N}},T=st(A(!0,1000000n));g=BigInt(Math.ceil(T*i));let S=p+g;if(b<S){let _=F(r,S+200n,{requireGenesis:!1});if(_.inputs.length>m.inputs.length){m=_;continue}throw new X(`not enough funds: need ${S} sat, have ${b} sat`,{needSats:S,haveSats:b})}w=b-S,x=w>=K,x||(g=b-p,w=0n);let P=A(x,w),I={},O=0;return x&&(I.change=O++),I.certificate=O++,I.opReturn=O++,I.beacon=O++,{tld:c,displayName:`.${c}`,category:s.token.category,transaction:P,sourceOutputs:k.map(xt),inputUtxos:k,outputMap:I,payload:d,costs:{certificateDustSats:R,beaconDustSats:B,serviceFeeSats:0n,chainFeeSats:g,changeSats:w,totalInputSats:b,netCostSats:g+B}}}throw new Error("could not converge on a fee \u2014 please retry")}function _t({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=(y,p)=>({version:2,locktime:0,inputs:l.map(yt),outputs:[{lockingBytecode:r,valueSatoshis:n},...y?[{lockingBytecode:r,valueSatoshis:p}]:[]]}),d=BigInt(Math.ceil(st(h(!0,1000000n))*o));if(c<n+d){let y=BigInt(Math.ceil(st(h(!1,0n))*o));if(c<=y+K)throw new X(`not enough funds to prepare the wallet: have ${c} sat`,{needSats:y+K,haveSats:c});return{transaction:{version:2,locktime:0,inputs:l.map(yt),outputs:[{lockingBytecode:r,valueSatoshis:c-y}]},sourceOutputs:l.map(xt),inputUtxos:l,costs:{chainFeeSats:y}}}let u=c-n-d,f=u>=K;return{transaction:h(f,u),sourceOutputs:l.map(xt),inputUtxos:l,costs:{chainFeeSats:f?d:c-n}}}throw new Error("could not converge on a fee \u2014 please retry")}function bt(t){return t.some(e=>e.vout===0&&!e.token)}function en({transaction:t,sourceOutputs:e},{broadcast:n=!0,userPrompt:o}={}){return{transaction:t,sourceOutputs:e,broadcast:n,...o?{userPrompt:o}:{}}}import{generateSigningSerializationBCH as bo,hash256 as on,secp256k1 as ko,encodeTransaction as So,binToHex as pe}from"@bitauth/libauth";var nn=65;function rt(t,e,n){let o={...t,inputs:t.inputs.map((r,a)=>{let i=e[a],l=n(pe(i.lockingBytecode));if(!l)throw new Error(`no key for input ${a} \u2014 cannot sign`);let c=bo({inputIndex:a,sourceOutputs:e,transaction:t},{coveredBytecode:i.lockingBytecode,signingSerializationType:Uint8Array.of(nn)}),h=on(c),d=ko.signMessageHashSchnorr(l.privateKey,h);if(typeof d=="string")throw new Error(`signing failed on input ${a}: ${d}`);let u=Uint8Array.from([...d,nn]);return{...r,unlockingBytecode:Uint8Array.from([u.length,...u,l.publicKey.length,...l.publicKey])}})},s=So(o);return{transaction:o,hex:pe(s),txid:ge(s)}}function ge(t){return pe(on(t).slice().reverse())}function ye(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 ge(e)}var L={network:E.id,addressPrefix:E.prefix,explorerTx:E.explorerTx,selfHosted:null,get electrum(){return this.selfHosted?[this.selfHosted,...Ut]:Ut},beacon:E.beacon,tldBeacon:E.tldBeacon,serviceFee:{address:E.operatorAddress,sats:10000n},feeRate:1,wizardConnect:{dappName:"Silent Mode",dappIcon:"https://silentmode.st/icon.png"},faucets:E.faucets};function To(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 dn,binToHex as mt,decodeTransaction as Bo,lockingBytecodeToCashAddress as Io,sha256 as Po,utf8ToBin as No,binToBase64 as Ro}from"@bitauth/libauth";import{encodeTransaction as we,decodeTransaction as sn,generateSigningSerializationBCH as rn,hash256 as xe,hash160 as Eo,secp256k1 as an,hexToBin as lt,binToHex as $,utf8ToBin as cn}from"@bitauth/libauth";var Mt=65,me=195,it=(t,e)=>({outpointTransactionHash:lt(t.txid),outpointIndex:t.vout,sequenceNumber:4294967294,unlockingBytecode:e??de()}),ut=t=>t?{amount:BigInt(t.amount??0),category:lt(t.category),...t.nft?{nft:{capability:t.nft.capability,commitment:lt(t.nft.commitment||"")}}:{}}:void 0,be=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||"")}}:{}}}:{}}),ke=t=>({lockingBytecode:lt(t.lockingBytecode),valueSatoshis:BigInt(t.valueSatoshis??t.satoshis),...t.token?{token:ut(t.token)}:{}}),dt=(t,e)=>({...it(t,e),lockingBytecode:t.lockingBytecode instanceof Uint8Array?t.lockingBytecode:lt(t.lockingBytecode),valueSatoshis:BigInt(t.satoshis),...t.token?{token:ut(t.token)}:{}});function ln(t,e,n,o,s){let r=e[n],a=rn({inputIndex:n,sourceOutputs:e,transaction:t},{coveredBytecode:r.lockingBytecode,signingSerializationType:Uint8Array.of(s)}),i=xe(a),l=an.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 vt(t,e,n,{sighash:o=Mt,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:ln(t,e,l,c,o)}:i})},a=we(r);return{transaction:r,hex:$(a),txid:$(xe(a).slice().reverse())}}function Oo({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!==$(cn(a)))throw new Error("certificate commitment does not match the name");let l=s(o),c=dt(e),h={version:2,locktime:0,inputs:[it(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=ln(h,[c],0,d,me),{v:1,name:a,seller:o,price_sats:i.toString(),category:e.token.category,partial_tx:$(we(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 _o(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 vo=t=>Uint8Array.from([118,169,20,...Eo(t),136,172]);function un(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=sn(lt(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!==$(cn(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}=_o(s.inputs[0].unlockingBytecode);if(i.length!==65||i[64]!==me)return n("input 0 is not signed SINGLE|ANYONECANPAY");let c=lt(r.lockingBytecode);if($(vo(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:ut(r.token)},d=rn({inputIndex:0,sourceOutputs:[h],transaction:s},{coveredBytecode:c,signingSerializationType:Uint8Array.of(me)});return an.verifySignatureSchnorr(i.slice(0,64),l,xe(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 Ao({listing:t,buyerAddress:e,buyerTokenAddress:n,utxos:o,records:s={},beaconAddress:r=ct,feeRate:a=1,addressToLockingBytecode:i}){let l=un(t);if(!l.ok)throw new Error("bad listing: "+l.error);let c=l.name,h=sn(lt(t.partial_tx)),d=t.source_output,u=h.inputs[0],f={...u,lockingBytecode:lt(d.lockingBytecode),valueSatoshis:BigInt(d.satoshis),token:ut(d.token)},y=h.outputs[0],p=y.valueSatoshis,m=i(e),g=i(n??e),w=i(r),x=J("UPD",c,s),v=p+R+B-BigInt(d.satoshis),k=F(o,v+400n,{requireGenesis:!1}),b=A=>we(A).length;for(let A=0;A<6;A++){let{inputs:T,totalSats:S}=k,P=(M,H)=>({version:2,locktime:0,inputs:[u,...T.map(W=>it(W))],outputs:[y,{lockingBytecode:g,valueSatoshis:R,token:ut(d.token)},{lockingBytecode:et(x),valueSatoshis:0n},{lockingBytecode:w,valueSatoshis:B},...M?[{lockingBytecode:m,valueSatoshis:H}]:[]]}),I=BigInt(Math.ceil(b(P(!0,1000000n))*a)),O=v+I;if(S<O){let M=F(o,O+200n,{requireGenesis:!1});if(M.inputs.length>T.length){k=M;continue}let H=new Error(`not enough funds: need ${O} sat, have ${S} sat`);throw H.needSats=O,H.haveSats=S,H}let _=S-O,U=_>=K;U||(_=0n);let N=P(U,_);return{name:c,transaction:N,sourceOutputs:[f,...T.map(M=>dt(M))],sellerInputIndex:0,costs:{priceSats:p,beaconDustSats:B,certificateDustSats:R,chainFeeSats:U?I:S-v,changeSats:_,totalInputSats:S}}}throw new Error("could not converge on a fee \u2014 please retry")}var Lo=90n,Do=100n;async function fn(t,e,n=L.addressPrefix){let s=(await Qt(t)).get(String(e).toLowerCase());if(!s?.mintScriptHex)return null;try{let r=dn(s.mintScriptHex),a=Io({bytecode:r,prefix:n,tokenSupport:!1});return typeof a=="string"?null:a.address}catch{return null}}function hn(t){let e=BigInt(t??0n),n=e*Lo/Do,o=e-n;return{tldOwnerFeeSats:n,platformFeeSats:o}}var Co=E.beaconOnly;async function Uo({electrum:t=L.electrum,WebSocket:e,beaconOk:n=!1}={}){let o=n?t:t.filter(s=>!Co.test(typeof s=="string"?s:s.url||""));return Ve(o,e)}async function Ht(t,e){let n=C(e),o=z(n),s=await pt({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:ue(n)}}async function Kt(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 q(t,[n]),h=C(e),d=h.indexOf("."),u=d<0?"bch":h.slice(d+1),f=BigInt(r.sats??0n),y=null,p=0n,m=f;if(f>0n){try{y=await fn(t,u)}catch{y=null}if(y&&y!==n){let g=hn(f);p=g.tldOwnerFeeSats,m=g.platformFeeSats}}return fe({name:e,ownerAddress:n,ownerTokenAddress:j(n),records:o,utxos:c,feeAddress:m>0n?r.address:null,feeSats:m,tldFeeAddress:p>0n?y:null,tldFeeSats:p,beaconAddress:L.beacon,feeRate:a,addressToLockingBytecode:D,cosignUtxo:i,cosignTokenAddress:l})}function pn(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 gn(t,{wallet:e,utxos:n,feeRate:o,onProgress:s}){if(bt(n))return{utxos:n,prepTxid:null};s("preparing-wallet");let r=_t({ownerAddress:e.address,utxos:n,feeRate:o,addressToLockingBytecode:D}),a=rt(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 Fo(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 Ht(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 q(t,e.watchedAddresses);if(c.filter(m=>!m.token).reduce((m,g)=>m+g.satoshis,0n)===0n)throw new Error("wallet is empty \u2014 fund the address first");let d=null;({utxos:c,prepTxid:d}=await gn(t,{wallet:e,utxos:c,feeRate:r,onProgress:i})),i("building");let u=await Kt(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 y={...u.transaction,inputs:u.transaction.inputs.map((m,g)=>g===f?{...m,unlockingBytecode:new Uint8Array}:m)},p=vt(y,u.sourceOutputs,m=>e.keyFor(m),{skip:[f]});return{name:u.name,displayName:u.displayName,category:u.category,tx:p.hex,sourceOutputs:u.sourceOutputs.map(be),cosignInputIndex:f,costs:u.costs,prepTxid:d}}function $o(t,e){let n=Bo(dn(String(t.tx||"")));if(typeof n=="string")throw new Error("invalid transaction: "+n);let o=(t.sourceOutputs||[]).map(ke);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(mt(c.lockingBytecode))){s.push(l);return}if(c.token?.nft&&!n.outputs.some(d=>d.token&&mt(d.token.category)===mt(c.token.category)&&mt(d.token.nft?.commitment??new Uint8Array)===mt(c.token.nft.commitment??new Uint8Array)&&mt(d.lockingBytecode)===mt(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=vt(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=L.serviceFee,feeRate:r=L.feeRate,cosign:a=null,onProgress:i=()=>{}}){i("checking-availability");let l=await Ht(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 q(t,e.watchedAddresses);if(c.filter(m=>!m.token).reduce((m,g)=>m+g.satoshis,0n)===0n)throw new Error("wallet is empty \u2014 fund the address first");let d=null;if(a&&(d=pn(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 gn(t,{wallet:e,utxos:c,feeRate:r,onProgress:i})),i("building");let f=await Kt(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 y=rt(f.transaction,f.sourceOutputs,m=>e.keyFor(m));i("broadcasting");let p=await tt(t,y.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:y.hex}}async function Ho(t,{wallet:e,tld:n,records:o={},serviceFee:s={address:null,sats:0n},feeRate:r=L.feeRate,tldListUrl:a=null,onProgress:i=()=>{}}){let l=Ot(n);if(i("checking-availability"),a)try{let p=await fetch(a);if(p.ok){let m=await p.json();if(Array.isArray(m.tlds)&&m.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 q(t,e.watchedAddresses);if(c.filter(p=>!p.token).reduce((p,m)=>p+m.satoshis,0n)===0n)throw new Error("wallet is empty \u2014 fund the address first");let d=null;if(!bt(c)){i("preparing-wallet");let p=_t({ownerAddress:e.address,utxos:c,feeRate:r,addressToLockingBytecode:D}),m=rt(p.transaction,p.sourceOutputs,g=>e.keyFor(g));d=await tt(t,m.hex),i("prepared",{txid:d}),c=[{txid:d,vout:0,satoshis:m.transaction.outputs[0].valueSatoshis,address:e.address,lockingBytecode:D(e.address)},...m.transaction.outputs.length>1?[{txid:d,vout:1,satoshis:m.transaction.outputs[1].valueSatoshis,address:e.address,lockingBytecode:D(e.address)}]:[]]}i("building");let u=$t({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=rt(u.transaction,u.sourceOutputs,p=>e.keyFor(p));i("broadcasting");let y=await tt(t,f.hex);return i("registered",{txid:y,category:u.category}),{tld:u.tld,category:u.category,txid:y,prepTxid:d,ownerAddress:e.address,certificateAddress:j(e.address),costs:u.costs,hex:f.hex}}async function Ko(t,{session:e,tld:n,records:o={},serviceFee:s={address:null,sats:0n},feeRate:r=L.feeRate,tldListUrl:a=null,onProgress:i=()=>{}}){let l=Ot(n);if(i("checking-availability"),a)try{let m=await fetch(a);if(m.ok){let g=await m.json();if(Array.isArray(g.tlds)&&g.tlds.some(x=>(x.tld||x)===l))throw new Error(`".${l}" is already registered as a TLD`)}}catch(m){if(/already registered/.test(m.message))throw m}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 q(t,c);if(d.filter(m=>!m.token).reduce((m,g)=>m+g.satoshis,0n)===0n)throw new Error("the connected wallet has no spendable coins");let u=null;if(!bt(d)){i("preparing-wallet");let m=_t({ownerAddress:h,utxos:d,feeRate:r,addressToLockingBytecode:D}),g=await e.signTransaction(m,{userPrompt:"One-time setup so your wallet can create a TLD certificate"});u=await Rt(t,e,g,i),i("prepared",{txid:u}),d=[{txid:u,vout:0,satoshis:m.transaction.outputs[0].valueSatoshis,address:h,lockingBytecode:D(h)},...d.filter(w=>!w.token&&!m.inputUtxos.some(x=>x.txid===w.txid&&x.vout===w.vout))]}i("building");let f=$t({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 y=await e.signTransaction(f,{userPrompt:`Register .${l} \u2014 the TLD certificate is minted to your own address`}),p=await Rt(t,e,y,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 Rt(t,e,n,o){let s=n.signedTransactionHash??ye(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 Wo(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 Ht(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 q(t,c);if(!d.some(p=>!p.token))throw new Error("the connected wallet has no spendable coins");if(!bt(d)){i("preparing-wallet");let p=_t({ownerAddress:h,utxos:d,feeRate:a,addressToLockingBytecode:D}),m=await e.signTransaction(p,{userPrompt:"One-time setup so your wallet can create a name certificate"}),g=await Rt(t,e,m,i);i("prepared",{txid:g}),d=[{txid:g,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 Kt(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`}),y=await Rt(t,e,f,i);return i("registered",{txid:y,category:u.category}),{name:u.name,displayName:u.displayName,category:u.category,txid:y,ownerAddress:h,certificateAddress:j(h),costs:u.costs}}async function Go(t,{addresses:e,category:n,rawName:o}){let s=await q(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 jo(t,{wallet:e,name:n,records:o,feeRate:s=L.feeRate,onProgress:r=()=>{}}){r("resolving");let a=C(n),l=(await pt({client:t})).get(z(a));if(!l)throw new Error(`"${z(a)}" is not registered`);r("loading-coins");let c=await q(t,e.watchedAddresses),h=c.find(y=>y.token?.category===l.category&&y.token?.nft);if(!h)throw new Error(`this wallet does not hold the certificate for "${z(a)}" \u2014 only the owner can change its records`);r("building");let d=Nt({name:n,ownerAddress:e.address,ownerTokenAddress:j(e.address),records:o,certificateUtxo:h,utxos:c.filter(y=>!y.token),beaconAddress:L.beacon,feeRate:s,addressToLockingBytecode:D});r("signing");let u=rt(d.transaction,d.sourceOutputs,y=>e.keyFor(y));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 yn(t,e,n=L.beacon){let o=await Qe(t,e.txid,!0),s=mt(D(n));return(o?.vout??[]).some(r=>r.scriptPubKey?.hex===s)}async function qo(t,{wallet:e,name:n,feeRate:o=L.feeRate,onProgress:s=()=>{}}){s("resolving");let r=C(n),i=(await pt({client:t})).get(z(r));if(!i)throw new Error(`"${z(r)}" is not registered`);s("loading-coins");let l=p=>p.token?.category===i.category&&p.token?.nft,c=await q(t,e.watchedAddresses),h=c.find(l);if(!h)throw new Error(`this wallet does not hold the certificate for "${z(r)}" \u2014 only the owner can release it`);let d=null;if(!await yn(t,h)){s("anchoring");let p=Nt({name:n,ownerAddress:e.address,ownerTokenAddress:j(e.address),records:i.records??{},certificateUtxo:h,utxos:c.filter(g=>!g.token),beaconAddress:L.beacon,feeRate:o,addressToLockingBytecode:D}),m=rt(p.transaction,p.sourceOutputs,g=>e.keyFor(g));d=await tt(t,m.hex),s("anchored",{txid:d}),h=null;for(let g=0;g<12&&!h;g++)await new Promise(w=>setTimeout(w,1500)),c=await q(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=he({name:n,ownerAddress:e.address,certificateUtxo:h,utxos:c.filter(p=>!p.token),beaconAddress:L.beacon,feeRate:o,addressToLockingBytecode:D});s("signing");let f=rt(u.transaction,u.sourceOutputs,p=>e.keyFor(p));s("broadcasting");let y=await tt(t,f.hex);return s("released",{txid:y}),{name:u.name,displayName:u.displayName,category:u.category,txid:y,anchorTxid:d,costs:u.costs}}async function zo(t,{session:e,name:n,records:o,feeRate:s=L.feeRate,onProgress:r=()=>{}}){r("resolving");let a=C(n),l=(await pt({client:t})).get(z(a));if(!l)throw new Error(`"${z(a)}" is not registered`);r("reading-wallet");let c=await e.getAddresses(),h=await q(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 "${z(a)}" \u2014 only the owner can change its records`);r("building");let u=Nt({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`}),y=await Rt(t,e,f,r);return r("updated",{txid:y}),{name:u.name,displayName:u.displayName,category:u.category,txid:y,records:o,costs:u.costs}}async function Yo(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 q(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=tn({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=rt(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 Vo(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(Se(n)),s=Po.hash(No(o)),r=t.signMessage(s);return{...e,sig:Ro(r)}}function Se(t){if(t!=null){if(Array.isArray(t))return t.map(Se).filter(e=>e!==void 0);if(typeof t=="object"){let e={};for(let n of Object.keys(t).sort()){let o=Se(t[n]);o!==void 0&&(e[n]=o)}return e}return t}}async function Xo(t,e){let n=await q(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:bt(n)}}import{hexToBin as Q,binToHex as nt,encodeDataPush as G,bigIntToVmNumber as Gt,hash256 as Te,hash160 as Jo,encodeLockingBytecodeP2sh32 as Qo,encodeLockingBytecodeP2pkh as bn,lockingBytecodeToCashAddress as Zo,OpcodesBCH as ts,numberToBinUint32LE as dr,binToNumberUint32LE as wn,secp256k1 as kn,sha256 as es,generateSigningSerializationBCH as ns,encodeTransaction as Sn,flattenBinArray as At}from"@bitauth/libauth";var mn={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 os=2,Ee=1200,ss=7200,rs=t=>{let e=ts[t];if(e===void 0)throw new Error("unknown opcode "+t);return Uint8Array.of(e)};function is(t){let e=t.trim().split(/\s+/).filter(Boolean).map(n=>n.startsWith("OP_")?rs(n):G(Q(n)));return At(e)}var as=is(mn.bytecode),Wt=t=>G(Gt(BigInt(t))),cs=0,xn=1;function ls(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 Oe({oraclePk:t,sellerPkh:e,targetCents:n,floorSats:o,ceilSats:s,maxAgeSecs:r=Ee}){if(!(BigInt(n)>0n)||!(BigInt(o)>0n)||BigInt(s)<BigInt(o))throw new Error("bad listing terms");return At([Wt(r),Wt(s),Wt(o),Wt(n),G(Q(e)),G(Q(t)),as])}var jt=t=>Qo(Te(t));function _e(t,e=E.prefix){let n=Zo({bytecode:jt(t),prefix:e});if(typeof n=="string")throw new Error(n);return n.address}function Tn({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 En=t=>({ts:wn(t.slice(0,4)),priceCents:wn(t.slice(4,8)),outpointTxid:nt(t.slice(8,40).slice().reverse())});function On(t,e,n){return kn.verifySignatureSchnorr(n,t,es.hash(e))===!0}var ve=(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(Sn(c.transaction).length*n)),d=e+h;if(l<d){let y=F(t,d+200n,{requireGenesis:s});if(y.inputs.length>i.length){r=y;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 us({name:t,certificateUtxo:e,utxos:n,sellerAddress:o,oraclePk:s,targetCents:r,floorSats:a,ceilSats:i,maxAgeSecs:l=Ee,records:c={},beaconAddress:h=ct,feeRate:d=1,addressToLockingBytecode:u}){let f=C(t);if(!e?.token?.nft)throw new Error("certificateUtxo does not carry a certificate");let y=u(o),p=ls(nt(u(e.address||o))),m=Oe({oraclePk:s,sellerPkh:p,targetCents:r,floorSats:a,ceilSats:i,maxAgeSecs:l}),g=jt(m),w=J("UPD",f,c),x=n.filter(b=>!b.token),v=R+B-BigInt(e.satoshis);return{...ve(x,v>0n?v:0n,d,(b,A,T)=>({transaction:{version:2,locktime:0,inputs:[it(e),...b.map(S=>it(S))],outputs:[{lockingBytecode:g,valueSatoshis:R,token:ut(e.token)},{lockingBytecode:et(w),valueSatoshis:0n},{lockingBytecode:u(h),valueSatoshis:B},...A?[{lockingBytecode:y,valueSatoshis:T}]:[]]},sourceOutputs:[dt(e),...b.map(S=>dt(S))]})),name:f,redeem:m,redeemHex:nt(m),address:_e(m,o.split(":")[0]),sellerPkh:p,covenantVout:0}}function _n(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:jt(e),token:t.token}}}function ds({listing:t,quote:e,buyerAddress:n,buyerTokenAddress:o,utxos:s,records:r={},beaconAddress:a=ct,feeRate:i=1,addressToLockingBytecode:l}){let c=C(t.name),h=Q(e.message),d=Q(e.signature);if(!On(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:y}=En(h);if(y!==String(t.outpoint.txid).toLowerCase())throw new Error("quote was issued for a different listing");let p=Tn({targetCents:t.target_cents,priceCents:f,floorSats:t.floor_sats,ceilSats:t.ceil_sats}),{redeem:m,utxo:g}=_n(t),w=bn(Q(t.seller_pkh)),x=At([G(d),G(h),G(Gt(BigInt(cs))),G(m)]),v=l(n),k=l(o??n),b=J("UPD",c,r),A=s.filter(P=>!P.token),T=p+R+B-g.satoshis;return{...ve(A,T,i,(P,I,O)=>({transaction:{version:2,locktime:Math.max(0,u-ss),inputs:[it(g,x),...P.map(_=>it(_))],outputs:[{lockingBytecode:w,valueSatoshis:p},{lockingBytecode:k,valueSatoshis:R,token:ut(g.token)},{lockingBytecode:et(b),valueSatoshis:0n},{lockingBytecode:l(a),valueSatoshis:B},...I?[{lockingBytecode:v,valueSatoshis:O}]:[]]},sourceOutputs:[dt(g),...P.map(_=>dt(_))]})),name:c,covenantInputIndex:0,priceSats:p,priceCents:f,quoteTs:u}}function fs({listing:t,sellerAddress:e,sellerTokenAddress:n,utxos:o,records:s={},beaconAddress:r=ct,feeRate:a=1,addressToLockingBytecode:i,keyFor:l}){let c=C(t.name),{redeem:h,utxo:d}=_n(t),u=bn(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 y=f.privateKey,p=f.publicKey,m=i(n??e),g=J("UPD",c,s),w=o.filter(_=>!_.token),x=R+B-d.satoshis,v=At([G(new Uint8Array(65)),G(p),G(Gt(BigInt(xn))),G(h)]),k=ve(w,x>0n?x:0n,a,(_,U,N)=>({transaction:{version:2,locktime:0,inputs:[it(d,v),..._.map(M=>it(M))],outputs:[{lockingBytecode:m,valueSatoshis:R,token:ut(d.token)},{lockingBytecode:et(g),valueSatoshis:0n},{lockingBytecode:i(r),valueSatoshis:B},...U?[{lockingBytecode:i(e),valueSatoshis:N}]:[]]},sourceOutputs:[dt(d),..._.map(M=>dt(M))]})),b=vt(k.transaction,k.sourceOutputs,l,{skip:[0]}),A=ns({inputIndex:0,sourceOutputs:k.sourceOutputs,transaction:b.transaction},{coveredBytecode:h,signingSerializationType:Uint8Array.of(Mt)}),T=kn.signMessageHashSchnorr(y,Te(A));if(typeof T=="string")throw new Error(T);let S=At([T,Uint8Array.of(Mt)]),P=At([G(S),G(p),G(Gt(BigInt(xn))),G(h)]),I={...b.transaction,inputs:b.transaction.inputs.map((_,U)=>U===0?{..._,unlockingBytecode:P}:_)},O=Sn(I);return{name:c,transaction:I,sourceOutputs:k.sourceOutputs,hex:nt(O),txid:nt(Te(O).slice().reverse())}}function hs(t,{oraclePk:e}={}){let n=o=>({ok:!1,error:o});try{if(t?.kind!=="usd"||t.v!==os)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=Oe({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]||E.prefix;return _e(o,s)!==t.covenant_address?n("covenant address does not match"):nt(Jo(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(jt(o))}}catch(o){return n(String(o?.message||o))}}import{hash160 as ps,lockingBytecodeToCashAddress as gs,binToHex as wr}from"@bitauth/libauth";function vn(t){return Uint8Array.from([118,169,20,...ps(t),136,172])}function ys(t,e=E.prefix,n=!1){let o=gs({bytecode:vn(t),prefix:e,tokenSupport:n});if(typeof o=="string")throw new Error(`address encoding failed: ${o}`);return o.address}function ms(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 Dr}from"@bitauth/libauth";import{stringify as Ur}from"@bitauth/libauth";export{oe as BuiltInWallet,ro as CHIPNET_PREFIX,Ee as DEFAULT_MAX_AGE_SECS,Le as DEFAULT_NETWORK_ID,It as DEFAULT_PREFIX,X as InsufficientFundsError,io as MAINNET_PREFIX,E as NETWORK,Tt as NETWORKS,Ft as NoGenesisInputError,L as REGISTRAR,le as TLD_BEACON,D as addressToLockingBytecode,po as addressToScripthash,Lr as binToHex,tt as broadcast,Fo as buildCosignRequest,pt as buildIndex,Oo as buildListing,_t as buildPrepTx,fe as buildRegistrationTx,he as buildReleaseTx,$t as buildTldRegistrationTx,Nt as buildUpdateTx,ds as buildUsdBuyTx,fs as buildUsdCancelTx,us as buildUsdListingTx,Ht as checkAvailability,Ao as completeSale,Uo as connect,ms as describeGenesisRequirement,z as displayName,Go as findCertificateUtxo,pn as findTldCertificateUtxo,fn as findTldOwnerAddress,Xo as getBalance,Et as getNetwork,Je as getUtxos,q as getUtxosForAddresses,bt as hasGenesisInput,Dr as hexToBin,yn as isAnchored,C as normalizeName,Ot as normalizeTld,En as parseOracleMessage,ue as payloadBudget,Tn as payoutSats,To as priceSummary,ys as pubkeyToAddress,vn as pubkeyToLockingBytecode,Kt as quoteRegistration,Ho as registerTldWithBuiltInWallet,Ko as registerTldWithExternalWallet,Mo as registerWithBuiltInWallet,Wo as registerWithExternalWallet,qo as releaseWithBuiltInWallet,zt as requireBeacons,Qn as resolveName,jo as setRecordsWithBuiltInWallet,zo as setRecordsWithExternalWallet,Yo as setTldRecordsWithBuiltInWallet,$o as signCosignRequest,vt as signInputs,Vo as signRecordsManifest,rt as signTransaction,ke as sourceOutputFromJson,be as sourceOutputToJson,hn as splitServiceFee,Ur as stringify,j as toTokenAddress,en as toWcTransactionObject,ge as txidOf,ye as txidOfHex,_e as usdListingAddress,Oe as usdListingRedeem,un as verifyListing,On as verifyOracleMessage,hs as verifyUsdListing};
|