diff --git a/js/bns-register.js b/js/bns-register.js index 47c31ba..7d8435d 100644 --- a/js/bns-register.js +++ b/js/bns-register.js @@ -1,7 +1,7 @@ -import{generateBip39Mnemonic as dn,deriveSeedFromBip39Mnemonic as ye,deriveHdPrivateNodeFromSeed as hn,deriveHdPath as pn,secp256k1 as me,hash160 as fn,encodeCashAddress as Ko,lockingBytecodeToCashAddress as gn,cashAddressToLockingBytecode as Go,binToHex as yn,hexToBin as Wo,utf8ToBin as ke,binToBase64 as Ht,base64ToBin as Kt}from"@bitauth/libauth";var Et="bchtest";var Gt="m/44'/145'/0'",mn=5,At="bns.wallet.v1";function be(t){let e=fn(t);return Uint8Array.from([118,169,20,...e,136,172])}function we(t,e,n){let o=gn({bytecode:be(t),prefix:e,tokenSupport:n});if(typeof o=="string")throw new Error(`address encoding failed: ${o}`);return o.address}var Wt=class t{constructor(e,n,o=Et,s=Gt){this.mnemonic=e,this.prefix=o,this.accountPath=s,this._root=hn(n),this._keys=new Map,this._derive()}static async create(e=Et,n=Gt){let o=dn();return new t(o,await ye(o),e,n)}static async fromMnemonic(e,n=Et,o=Gt){let s=String(e).trim().toLowerCase().replace(/\s+/g," "),r=await ye(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;oe.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=me.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 xe(e,n),r=new Uint8Array(await crypto.subtle.encrypt({name:"AES-GCM",iv:o},s,ke(this.mnemonic)));return JSON.stringify({v:1,kdf:"PBKDF2-SHA256",iterations:qt,prefix:this.prefix,salt:Ht(n),iv:Ht(o),ct:Ht(r)})}static async decrypt(e,n){let o=typeof e=="string"?JSON.parse(e):e,s=await xe(n,Kt(o.salt),o.iterations??qt),r;try{r=await crypto.subtle.decrypt({name:"AES-GCM",iv:Kt(o.iv)},s,Kt(o.ct))}catch{throw new Error("wrong password")}return t.fromMnemonic(new TextDecoder().decode(r),o.prefix??Et)}async save(e,n=globalThis.localStorage){n.setItem(At,await this.encrypt(e))}static async load(e,n=globalThis.localStorage){let o=n.getItem(At);return o?t.decrypt(o,e):null}static exists(e=globalThis.localStorage){return!!e?.getItem(At)}static forget(e=globalThis.localStorage){e.removeItem(At)}},qt=25e4;async function xe(t,e,n=qt){let o=await crypto.subtle.importKey("raw",ke(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 Bt=["wss://silentmode.st/electrum","wss://chipnet.bch.ninja:50004","wss://chipnet.imaginary.cash:50004","wss://tbch4.loping.net:62002"],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(` +import{generateBip39Mnemonic as Bn,deriveSeedFromBip39Mnemonic as Ae,deriveHdPrivateNodeFromSeed as In,deriveHdPath as Pn,secp256k1 as Be,hash160 as Nn,encodeCashAddress as ss,lockingBytecodeToCashAddress as Rn,cashAddressToLockingBytecode as rs,binToHex as Ln,hexToBin as is,utf8ToBin as Ne,binToBase64 as Yt,base64ToBin as Vt}from"@bitauth/libauth";var kt={chipnet:{id:"chipnet",label:"chipnet",prefix:"bchtest",beacon:"bchtest:qp8njaa9a3ahg7259s5qajnce526n0rttsq8qwx4jl",beaconScripthash:"e1cdbba719436f49acb4bf245b44df875c6d6b405eda46a9d3e736d138102f3b",tldBeacon:"bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh",tldBeaconScripthash:"c85db10e106606273422b2733b2a6fb8b35a4d0e7dbfb20cf59bdb0833c008b8",electrum:[{url:"wss://silentmode.st/electrum",ip:"195.184.247.106"},{url:"wss://coinspectrum.duckdns.org:50011",ip:"195.184.247.106"},{url:"wss://chipnet.bch.ninja:50004",ip:"135.148.236.244"},{url:"wss://chipnet.imaginary.cash:50004",ip:"66.29.152.199"},{url:"wss://tbch4.loping.net:62002",ip:"183.89.202.207"}],beaconOnly:/silentmode\.st\/electrum|coinspectrum\.duckdns\.org:50011/,electrumListName:"electrum.bch",rootTldName:"tlds.bch",bootstrapTlds:["bch"],startHeight:2e5,hostingBucket:"bns",nameListUrl:"https://s3.silentmode.st:8600/bns/name-list.json",cdnIndexUrl:"https://dl.silentmode.st/bns-name-index.json",nostrTags:{names:"bns-name-list",tlds:"bns-tld-list"},explorerTx:"https://chipnet.imaginary.cash/tx/",faucets:[{name:"tbch.googol.cash",url:"https://tbch.googol.cash/"},{name:"chipnet.bch.ninja faucet",url:"https://chipnet.bch.ninja/faucet"}],operatorAddress:"bchtest:qzew3dqcsj0guwe5y3uxf9q2xs5ajgy9lca4z093cu",accountPath:"m/44'/145'/0'",bchnRpcPort:48332},mainnet:{id:"mainnet",label:"mainnet",prefix:"bitcoincash",beacon:null,beaconScripthash:null,tldBeacon:null,tldBeaconScripthash:null,electrum:[{url:"wss://bch.imaginary.cash:50004",ip:"67.223.119.97"},{url:"wss://electrum.imaginary.cash:50004",ip:"15.204.113.162"},{url:"wss://electroncash.dk:50004",ip:"87.63.200.138"},{url:"wss://bch.loping.net:50004",ip:"183.89.202.207"},{url:"wss://bch.soul-dev.com:50004",ip:"174.141.196.204"},{url:"wss://cashnode.bch.ninja:50004",ip:"135.148.236.246"}],beaconOnly:/(?!)/,electrumListName:"electrum.bch",rootTldName:"tlds.bch",bootstrapTlds:["bch"],startHeight:null,hostingBucket:"bns-mainnet",nameListUrl:"https://s3.silentmode.st:8600/bns-mainnet/name-list.json",cdnIndexUrl:"https://dl.silentmode.st/bns-mainnet-name-index.json",nostrTags:{names:"bns-mainnet-name-list",tlds:"bns-mainnet-tld-list"},explorerTx:"https://blockchair.com/bitcoin-cash/transaction/",faucets:[],operatorAddress:null,accountPath:"m/44'/145'/0'",bchnRpcPort:8332}},Se="chipnet";function gn(){let t=typeof globalThis<"u"?globalThis.BNS_NETWORK:null,e=typeof process<"u"&&process.env?process.env.BNS_NETWORK:null;return String(t||e||Se).trim().toLowerCase()}function Pt(t){if(t&&typeof t=="object")return t;let e=t||gn(),n=kt[e];if(!n)throw new Error(`unknown network "${e}" (known: ${Object.keys(kt).join(", ")})`);return n}var T=Pt();function zt(t=T){let e=Pt(t);if(!e.beaconScripthash||!e.tldBeaconScripthash)throw new Error(`${e.label}: beacon addresses are not pinned yet (see ROADMAP-MAINNET.md \xA76)`);return e}var jo=T.beacon,Yo=T.beaconScripthash,Vo=T.tldBeacon,Xo=T.tldBeaconScripthash,Jo=T.electrum,Qo=kt.chipnet.electrum,Zo=T.electrumListName,ke="BNS1";var Te="bch",mn=/^[a-z0-9-]{1,32}$/,Ee=/^[a-z0-9-]{1,16}$/,yn=/^[a-z0-9-]{1,32}(\.[a-z0-9-]{1,16})?$/;function wn(t){return t.includes(".")?t:t+"."+Te}var xn=t=>{let e=new Uint8Array(t.length/2);for(let n=0;n[...new TextEncoder().encode(t)].map(e=>e.toString(16).padStart(2,"0")).join("");function kn(t){let n=String(t).toLowerCase().trim().replace(/^[a-z]+:\/\//,"").split("/")[0].replace(/\.$/,"").split(".").filter(Boolean);if(n.length===0)throw new Error(`invalid name "${t}"`);let o,s;if(n.length===1?(o=n[0],s=Te):(s=n[n.length-1],o=n[n.length-2]),!mn.test(o)||!Ee.test(s))throw new Error(`invalid name "${t}" (allowed: