You are viewing a single comment's thread from:

RE: Propolis Wallet v2 (ZH)

in #propolis-wallet4 days ago (edited)
${r}`)}else t.writeVarint32(r);t.append(e.buffer)},gr=yr(),Pe=(n,t)=>(e,r)=>{e.writeVarint32(r.length);for(const[i,s]of r)n(e,i),t(e,s)},j=n=>(t,e)=>{t.writeVarint32(e.length);for(const r of e)n(t,r)},pt=n=>(t,e)=>{for(const[r,i]of n)try{i(t,e[r])}catch(s){throw s.message=`${r}: ${s.message}`,s}},zt=n=>(t,e)=>{e!==void 0?(t.writeByte(1),n(t,e)):t.writeByte(0)},J=pt([["weight_threshold",nt],["account_auths",Pe(w,ht)],["key_auths",Pe(_t,ht)]]),Ji=pt([["account",w],["weight",ht]]),rn=pt([["base",z],["quote",z]]),Xi=pt([["account_creation_fee",z],["maximum_block_size",nt],["hbd_interest_rate",ht]]),R=(n,t)=>{const e=pt(t);return(r,i)=>{r.writeVarint32(n),e(r,i)}},T={};T.account_create=R(O.account_create,[["fee",z],["creator",w],["new_account_name",w],["owner",J],["active",J],["posting",J],["memo_key",_t],["json_metadata",w]]);T.account_create_with_delegation=R(O.account_create_with_delegation,[["fee",z],["delegation",z],["creator",w],["new_account_name",w],["owner",J],["active",J],["posting",J],["memo_key",_t],["json_metadata",w],["extensions",j(lt)]]);T.account_update=R(O.account_update,[["account",w],["owner",zt(J)],["active",zt(J)],["posting",zt(J)],["memo_key",_t],["json_metadata",w]]);T.account_witness_proxy=R(O.account_witness_proxy,[["account",w],["proxy",w]]);T.account_witness_vote=R(O.account_witness_vote,[["account",w],["witness",w],["approve",It]]);T.cancel_transfer_from_savings=R(O.cancel_transfer_from_savings,[["from",w],["request_id",nt]]);T.change_recovery_account=R(O.change_recovery_account,[["account_to_recover",w],["new_recovery_account",w],["extensions",j(lt)]]);T.claim_account=R(O.claim_account,[["creator",w],["fee",z],["extensions",j(lt)]]);T.claim_reward_balance=R(O.claim_reward_balance,[["account",w],["reward_hive",z],["reward_hbd",z],["reward_vests",z]]);T.comment=R(O.comment,[["parent_author",w],["parent_permlink",w],["author",w],["permlink",w],["title",w],["body",w],["json_metadata",w]]);T.comment_options=R(O.comment_options,[["author",w],["permlink",w],["max_accepted_payout",z],["percent_hbd",ht],["allow_votes",It],["allow_curation_rewards",It],["extensions",j(br([pt([["beneficiaries",j(Ji)]])]))]]);T.convert=R(O.convert,[["owner",w],["requestid",nt],["amount",z]]);T.create_claimed_account=R(O.create_claimed_account,[["creator",w],["new_account_name",w],["owner",J],["active",J],["posting",J],["memo_key",_t],["json_metadata",w],["extensions",j(lt)]]);T.custom=R(O.custom,[["required_auths",j(w)],["id",ht],["data",gr]]);T.custom_json=R(O.custom_json,[["required_auths",j(w)],["required_posting_auths",j(w)],["id",w],["json",w]]);T.decline_voting_rights=R(O.decline_voting_rights,[["account",w],["decline",It]]);T.delegate_vesting_shares=R(O.delegate_vesting_shares,[["delegator",w],["delegatee",w],["vesting_shares",z]]);T.delete_comment=R(O.delete_comment,[["author",w],["permlink",w]]);T.escrow_approve=R(O.escrow_approve,[["from",w],["to",w],["agent",w],["who",w],["escrow_id",nt],["approve",It]]);T.escrow_dispute=R(O.escrow_dispute,[["from",w],["to",w],["agent",w],["who",w],["escrow_id",nt]]);T.escrow_release=R(O.escrow_release,[["from",w],["to",w],["agent",w],["who",w],["receiver",w],["escrow_id",nt],["hbd_amount",z],["hive_amount",z]]);T.escrow_transfer=R(O.escrow_transfer,[["from",w],["to",w],["hbd_amount",z],["hive_amount",z],["escrow_id",nt],["agent",w],["fee",z],["json_meta",w],["ratification_deadline",qt],["escrow_expiration",qt]]);T.feed_publish=R(O.feed_publish,[["publisher",w],["exchange_rate",rn]]);T.limit_order_cancel=R(O.limit_order_cancel,[["owner",w],["orderid",nt]]);T.limit_order_create=R(O.limit_order_create,[["owner",w],["orderid",nt],["amount_to_sell",z],["min_to_receive",z],["fill_or_kill",It],["expiration",qt]]);T.limit_order_create2=R(O.limit_order_create2,[["owner",w],["orderid",nt],["amount_to_sell",z],["exchange_rate",rn],["fill_or_kill",It],["expiration",qt]]);T.recover_account=R(O.recover_account,[["account_to_recover",w],["new_owner_authority",J],["recent_owner_authority",J],["extensions",j(lt)]]);T.request_account_recovery=R(O.request_account_recovery,[["recovery_account",w],["account_to_recover",w],["new_owner_authority",J],["extensions",j(lt)]]);T.reset_account=R(O.reset_account,[["reset_account",w],["account_to_reset",w],["new_owner_authority",J]]);T.set_reset_account=R(O.set_reset_account,[["account",w],["current_reset_account",w],["reset_account",w]]);T.set_withdraw_vesting_route=R(O.set_withdraw_vesting_route,[["from_account",w],["to_account",w],["percent",ht],["auto_vest",It]]);T.transfer=R(O.transfer,[["from",w],["to",w],["amount",z],["memo",w]]);T.transfer_from_savings=R(O.transfer_from_savings,[["from",w],["request_id",nt],["to",w],["amount",z],["memo",w]]);T.transfer_to_savings=R(O.transfer_to_savings,[["from",w],["to",w],["amount",z],["memo",w]]);T.transfer_to_vesting=R(O.transfer_to_vesting,[["from",w],["to",w],["amount",z]]);T.vote=R(O.vote,[["voter",w],["author",w],["permlink",w],["weight",Gi]]);T.withdraw_vesting=R(O.withdraw_vesting,[["account",w],["vesting_shares",z]]);T.witness_update=R(O.witness_update,[["owner",w],["url",w],["block_signing_key",_t],["props",Xi],["fee",z]]);T.witness_set_properties=R(O.witness_set_properties,[["owner",w],["props",Pe(w,gr)],["extensions",j(lt)]]);T.account_update2=R(O.account_update2,[["account",w],["owner",zt(J)],["active",zt(J)],["posting",zt(J)],["memo_key",zt(_t)],["json_metadata",w],["posting_json_metadata",w],["extensions",j(lt)]]);T.create_proposal=R(O.create_proposal,[["creator",w],["receiver",w],["start_date",qt],["end_date",qt],["daily_pay",z],["subject",w],["permlink",w],["extensions",j(lt)]]);T.update_proposal_votes=R(O.update_proposal_votes,[["voter",w],["proposal_ids",j(mr)],["approve",It],["extensions",j(lt)]]);T.remove_proposal=R(O.remove_proposal,[["proposal_owner",w],["proposal_ids",j(mr)],["extensions",j(lt)]]);const Qi=pt([["end_date",qt]]);T.update_proposal=R(O.update_proposal,[["proposal_id",wr],["creator",w],["daily_pay",z],["subject",w],["permlink",w],["extensions",j(br([lt,Qi]))]]);T.collateralized_convert=R(O.collateralized_convert,[["owner",w],["requestid",nt],["amount",z]]);T.recurrent_transfer=R(O.recurrent_transfer,[["from",w],["to",w],["amount",z],["memo",w],["recurrence",ht],["executions",ht],["extensions",j(pt([["type",In],["value",pt([["pair_id",In]])]]))]]);const ts=(n,t)=>{const e=T[t[0]];if(!e)throw new Error(`No serializer for operation: ${t[0]}`);try{e(n,t[1])}catch(r){throw r.message=`${t[0]}: ${r.message}`,r}},es=pt([["ref_block_num",ht],["ref_block_prefix",nt],["expiration",qt],["operations",j(ts)],["extensions",j(w)]]),ns=pt([["from",_t],["to",_t],["nonce",wr],["check",nt],["encrypted",yr()]]),_r={Asset:z,Memo:ns,Price:rn,PublicKey:_t,String:w,Transaction:es,UInt16:ht,UInt32:nt};let Fe=0,$n=0;class Ae extends Error{constructor(t){super(t.message),this.name="RPCError",this.stack=void 0,this.code=t.code,"data"in t&&(this.data=t.data)}}const vr=async(n,t,e,r=ft.timeout,i=!1)=>{const s=Math.floor(Math.random()*1e8),c={jsonrpc:"2.0",method:t,params:e,id:s};try{const o=await(await fetch(n,{method:"POST",body:JSON.stringify(c),headers:{"Content-Type":"application/json"},signal:AbortSignal.timeout(r)})).json();if(!o||typeof o.id>"u"||o.id!==s||o.jsonrpc!=="2.0")throw new Error("JSONRPC id missmatch");if("result"in o)return o.result;if("error"in o){const l=o.error;throw"message"in l&&"code"in l?new Ae(l):o.error}throw o}catch(a){if(a instanceof Ae)throw a;if(i)return vr(n,t,e,r,!1);throw a}},_e=async(n,t=[],e=ft.timeout,r=ft.retry)=>{if(!Array.isArray(ft.nodes))throw new Error("config.nodes is not an array");const i=ft.nodes[Fe];try{return await vr(i,n,t,e)}catch(s){if(s instanceof Ae||($n++,$n>r))throw s;return rs(),_e(n,t,e,r)}},rs=(n=Fe+1)=>{n>ft.nodes.length-1&&(n=0),Fe=n},Bn=n=>new Promise(t=>setTimeout(t,n)),is=gt(ft.chain_id);class sn{constructor(t){this.expiration=6e4,this.createTransaction=async e=>{const r=await _e("condenser_api.get_dynamic_global_properties",[]),i=gt(r.head_block_id),s=Number(new Uint32Array(i.buffer,i.byteOffset+4,1)[0]),c=new Date(Date.now()+e).toISOString().slice(0,-5);this.transaction={expiration:c,extensions:[],operations:[],ref_block_num:r.head_block_number&65535,ref_block_prefix:s,signatures:[]}},t?.transaction&&(t.transaction instanceof sn?(this.transaction=t.transaction.transaction,this.expiration=t.transaction.expiration):this.transaction=t.transaction,this.txId=this.digest().txId),t?.expiration&&(this.expiration=t.expiration)}async addOperation(t,e){this.transaction||await this.createTransaction(this.expiration),this.transaction.operations.push([t,e])}sign(t){if(!this.transaction)throw new Error("First create a transaction by .addOperation()");if(this.transaction){const{digest:e,txId:r}=this.digest();Array.isArray(t)||(t=[t]);for(const i of t){const s=i.sign(e);this.transaction.signatures.push(s.customToString())}return this.txId=r,this.transaction}else throw new Error("No transaction to sign")}async broadcast(t=!1){if(!this.transaction)throw new Error("Attempted to broadcast an empty transaction. Add operations by .addOperation()");if(this.transaction.signatures.length===0)throw new Error("Attempted to broadcast a transaction with no signatures. Sign using .sign(keys)");try{await _e("condenser_api.broadcast_transaction",[this.transaction])}catch(i){if(!(i instanceof Ae&&i.message.includes("Duplicate transaction check failed")))throw i}if(this.txId||(this.txId=this.digest().txId),!t)return{tx_id:this.txId,status:"unknown"};await Bn(1e3);let e=await this.checkStatus(),r=1;for(;e?.status!=="within_irreversible_block"&&e?.status!=="expired_irreversible"&&e?.status!=="too_old";)await Bn(1e3+r*300),e=await this.checkStatus(),r++;return{tx_id:this.txId,status:e.status}}digest(){if(!this.transaction)throw new Error("First create a transaction by .addOperation()");const t=new N(N.DEFAULT_CAPACITY,N.LITTLE_ENDIAN),e={...this.transaction};try{_r.Transaction(t,e)}catch(c){throw new Error("Unable to serialize transaction: "+c)}t.flip();const r=new Uint8Array(t.toBuffer()),i=yt(Zt(r)).slice(0,40);return{digest:Zt(new Uint8Array([...is,...r])),txId:i}}addSignature(t){if(!this.transaction)throw new Error("First create a transaction by .create(operations)");if(typeof t!="string")throw new Error("Signature must be string");if(t.length!==130)throw new Error("Signature must be 130 characters long");return this.transaction.signatures.push(t),this.transaction}async checkStatus(){return this.txId||(this.txId=this.digest().txId),_e("transaction_status_api.find_transaction",{transaction_id:this.txId,expiration:this.transaction?.expiration})}}const xr=new Uint8Array([128]);class Et{constructor(t){this.key=t;try{At.getPublicKey(t)}catch{throw new Error("invalid private key")}}static from(t){return typeof t=="string"?Et.fromString(t):new Et(t)}static fromString(t){return new Et(os(t).subarray(1))}static fromSeed(t){return typeof t=="string"&&(/^[0-9a-fA-F]+$/.test(t)?t=gt(t):t=new TextEncoder().encode(t)),new Et(Zt(t))}static fromLogin(t,e,r="active"){const i=t+r+e;return Et.fromSeed(i)}sign(t){const e=At.sign(t,this.key,{extraEntropy:!0,format:"recovered",prehash:!1}),r=parseInt(yt(e.subarray(0,1)),16);return ke.from((r+31).toString(16)+yt(e.subarray(1)))}createPublic(t){return new at(At.getPublicKey(this.key),t)}toString(){return ss(new Uint8Array([...xr,...this.key]))}inspect(){const t=this.toString();return`PrivateKey: ${t.slice(0,6)}...${t.slice(-6)}`}getSharedSecret(t){const e=At.getSharedSecret(this.key,t.key);return Zn(e.subarray(1))}static randomKey(){return new Et(At.keygen().secretKey)}}const Er=n=>Zt(Zt(n)),ss=n=>{const t=Er(n);return re.encode(new Uint8Array([...n,...t.slice(0,4)]))},os=n=>{const t=re.decode(n);if(!kn(t.slice(0,1),xr))throw new Error("Private key network id mismatch");const e=t.slice(-4),r=t.slice(0,-4),i=Er(r).slice(0,4);if(!kn(e,i))throw new Error("Private key checksum mismatch");return r},kn=(n,t)=>{if(n===t)return!0;if(n.byteLength!==t.byteLength)return!1;const e=n.byteLength;let r=0;for(;r<e&&n[r]===t[r];)r++;return r===e};/*! noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com) */function cs(n){return n instanceof Uint8Array||ArrayBuffer.isView(n)&&n.constructor.name==="Uint8Array"}function St(n,t,e=""){const r=cs(n),i=n?.length,s=t!==void 0;if(!r||s&&i!==t){const c=e&&`"${e}" `,a=s?` of length ${t}`:"",o=r?`length=${i}`:`type=${typeof n}`;throw new Error(c+"expected Uint8Array"+a+", got "+o)}return n}function Ot(n){return new Uint32Array(n.buffer,n.byteOffset,Math.floor(n.byteLength/4))}function oe(...n){for(let t=0;t<n.length;t++)n[t].fill(0)}const as=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function ls(n,t){return n.buffer===t.buffer&&n.byteOffset<t.byteOffset+t.byteLength&&t.byteOffset<n.byteOffset+n.byteLength}function Sr(n,t){if(ls(n,t)&&n.byteOffset<t.byteOffset)throw new Error("complex overlap of input and output is not supported")}const ds=(n,t)=>{function e(r,...i){if(St(r,void 0,"key"),!as)throw new Error("Non little-endian hardware is not yet supported");if(n.nonceLength!==void 0){const d=i[0];St(d,n.varSizeNonce?void 0:n.nonceLength,"nonce")}const s=n.tagLength;s&&i[1]!==void 0&&St(i[1],void 0,"AAD");const c=t(r,...i),a=(d,f)=>{if(f!==void 0){if(d!==2)throw new Error("cipher output not supported");St(f,void 0,"output")}};let o=!1;return{encrypt(d,f){if(o)throw new Error("cannot encrypt() twice with same key + nonce");return o=!0,St(d),a(c.encrypt.length,f),c.encrypt(d,f)},decrypt(d,f){if(St(d),s&&d.length<s)throw new Error('"ciphertext" expected length bigger than tagLength='+s);return a(c.decrypt.length,f),c.decrypt(d,f)}}}return Object.assign(e,n),e};function Ar(n,t,e=!0){if(t===void 0)return new Uint8Array(n);if(t.length!==n)throw new Error('"output" expected Uint8Array of length '+n+", got: "+t.length);if(e&&!ee(t))throw new Error("invalid output, must be aligned");return t}function ee(n){return n.byteOffset%4===0}function se(n){return Uint8Array.from(n)}const Dt=16,us=283;function fs(n){if(![16,24,32].includes(n.length))throw new Error('"aes key" expected Uint8Array of length 16/24/32, got length='+n.length)}function on(n){return n<<1^us&-(n>>7)}function Qt(n,t){let e=0;for(;t>0;t>>=1)e^=n&-(t&1),n=on(n);return e}const je=(()=>{const n=new Uint8Array(256);for(let e=0,r=1;e<256;e++,r^=on(r))n[e]=r;const t=new Uint8Array(256);t[0]=99;for(let e=0;e<255;e++){let r=n[255-e];r|=r<<8,t[n[e]]=(r^r>>4^r>>5^r>>6^r>>7^99)&255}return oe(n),t})(),hs=je.map((n,t)=>je.indexOf(t)),ps=n=>n<<24|n>>>8,De=n=>n<<8|n>>>24;function Lr(n,t){if(n.length!==256)throw new Error("Wrong sbox length");const e=new Uint32Array(256).map((l,d)=>t(n[d])),r=e.map(De),i=r.map(De),s=i.map(De),c=new Uint32Array(256*256),a=new Uint32Array(256*256),o=new Uint16Array(256*256);for(let l=0;l<256;l++)for(let d=0;d<256;d++){const f=l*256+d;c[f]=e[l]^r[d],a[f]=i[l]^s[d],o[f]=n[l]<<8|n[d]}return{sbox:n,sbox2:o,T0:e,T1:r,T2:i,T3:s,T01:c,T23:a}}const cn=Lr(je,n=>Qt(n,3)<<24|n<<16|n<<8|Qt(n,2)),Ir=Lr(hs,n=>Qt(n,11)<<24|Qt(n,13)<<16|Qt(n,9)<<8|Qt(n,14)),ms=(()=>{const n=new Uint8Array(16);for(let t=0,e=1;t<16;t++,e=on(e))n[t]=e;return n})();function $r(n){St(n);const t=n.length;fs(n);const{sbox2:e}=cn,r=[];ee(n)||r.push(n=se(n));const i=Ot(n),s=i.length,c=o=>bt(e,o,o,o,o),a=new Uint32Array(t+28);a.set(i);for(let o=s;o<a.length;o++){let l=a[o-1];o%s===0?l=c(ps(l))^ms[o/s-1]:s>6&&o%s===4&&(l=c(l)),a[o]=a[o-s]^l}return oe(...r),a}function ws(n){const t=$r(n),e=t.slice(),r=t.length,{sbox2:i}=cn,{T0:s,T1:c,T2:a,T3:o}=Ir;for(let l=0;l<r;l+=4)for(let d=0;d<4;d++)e[l+d]=t[r-l-4+d];oe(t);for(let l=4;l<r-4;l++){const d=e[l],f=bt(i,d,d,d,d);e[l]=s[f&255]^c[f>>>8&255]^a[f>>>16&255]^o[f>>>24]}return e}function Rt(n,t,e,r,i,s){return n[e<<8&65280|r>>>8&255]^t[i>>>8&65280|s>>>24&255]}function bt(n,t,e,r,i){return n[t&255|e&65280]|n[r>>>16&255|i>>>16&65280]<<16}function Un(n,t,e,r,i){const{sbox2:s,T01:c,T23:a}=cn;let o=0;t^=n[o++],e^=n[o++],r^=n[o++],i^=n[o++];const l=n.length/4-2;for(let b=0;b<l;b++){const y=n[o++]^Rt(c,a,t,e,r,i),p=n[o++]^Rt(c,a,e,r,i,t),_=n[o++]^Rt(c,a,r,i,t,e),v=n[o++]^Rt(c,a,i,t,e,r);t=y,e=p,r=_,i=v}const d=n[o++]^bt(s,t,e,r,i),f=n[o++]^bt(s,e,r,i,t),m=n[o++]^bt(s,r,i,t,e),h=n[o++]^bt(s,i,t,e,r);return{s0:d,s1:f,s2:m,s3:h}}function bs(n,t,e,r,i){const{sbox2:s,T01:c,T23:a}=Ir;let o=0;t^=n[o++],e^=n[o++],r^=n[o++],i^=n[o++];const l=n.length/4-2;for(let b=0;b<l;b++){const y=n[o++]^Rt(c,a,t,i,r,e),p=n[o++]^Rt(c,a,e,t,i,r),_=n[o++]^Rt(c,a,r,e,t,i),v=n[o++]^Rt(c,a,i,r,e,t);t=y,e=p,r=_,i=v}const d=n[o++]^bt(s,t,i,r,e),f=n[o++]^bt(s,e,t,i,r),m=n[o++]^bt(s,r,e,t,i),h=n[o++]^bt(s,i,r,e,t);return{s0:d,s1:f,s2:m,s3:h}}function ys(n){if(St(n),n.length%Dt!==0)throw new Error("aes-(cbc/ecb).decrypt ciphertext should consist of blocks with size "+Dt)}function gs(n,t,e){St(n);let r=n.length;const i=r%Dt;if(!t&&i!==0)throw new Error("aec/(cbc-ecb): unpadded plaintext with disabled padding");ee(n)||(n=se(n));const s=Ot(n);if(t){let a=Dt-i;a||(a=Dt),r=r+a}e=Ar(r,e),Sr(n,e);const c=Ot(e);return{b:s,o:c,out:e}}function _s(n,t){if(!t)return n;const e=n.length;if(!e)throw new Error("aes/pcks5: empty ciphertext not allowed");const r=n[e-1];if(r<=0||r>16)throw new Error("aes/pcks5: wrong padding");const i=n.subarray(0,-r);for(let s=0;s<r;s++)if(n[e-s-1]!==r)throw new Error("aes/pcks5: wrong padding");return i}function vs(n){const t=new Uint8Array(16),e=Ot(t);t.set(n);const r=Dt-n.length;for(let i=Dt-r;i<Dt;i++)t[i]=r;return e}const Br=ds({blockSize:16,nonceLength:16},function(t,e,r={}){const i=!r.disablePadding;return{encrypt(s,c){const a=$r(t),{b:o,o:l,out:d}=gs(s,i,c);let f=e;const m=[a];ee(f)||m.push(f=se(f));const h=Ot(f);let b=h[0],y=h[1],p=h[2],_=h[3],v=0;for(;v+4<=o.length;)b^=o[v+0],y^=o[v+1],p^=o[v+2],_^=o[v+3],{s0:b,s1:y,s2:p,s3:_}=Un(a,b,y,p,_),l[v++]=b,l[v++]=y,l[v++]=p,l[v++]=_;if(i){const S=vs(s.subarray(v*4));b^=S[0],y^=S[1],p^=S[2],_^=S[3],{s0:b,s1:y,s2:p,s3:_}=Un(a,b,y,p,_),l[v++]=b,l[v++]=y,l[v++]=p,l[v++]=_}return oe(...m),d},decrypt(s,c){ys(s);const a=ws(t);let o=e;const l=[a];ee(o)||l.push(o=se(o));const d=Ot(o);c=Ar(s.length,c),ee(s)||l.push(s=se(s)),Sr(s,c);const f=Ot(s),m=Ot(c);let h=d[0],b=d[1],y=d[2],p=d[3];for(let _=0;_+4<=f.length;){const v=h,S=b,L=y,I=p;h=f[_+0],b=f[_+1],y=f[_+2],p=f[_+3];const{s0:q,s1:Q,s2:W,s3:C}=bs(a,h,b,y,p);m[_++]=q^v,m[_++]=Q^S,m[_++]=W^L,m[_++]=C^I}return oe(...l),_s(c,i)}}}),xs=(n,t,e,r=Ls())=>kr(n,t,r,e),Es=(n,t,e,r,i)=>kr(n,t,e,r,i).message,kr=(n,t,e,r,i)=>{const s=typeof e=="bigint"?e:BigInt(e),c=n.getSharedSecret(t);let a=new N(N.DEFAULT_CAPACITY,N.LITTLE_ENDIAN);a.writeUint64(s),a.append(c),a.flip();const o=Zn(new Uint8Array(a.toBuffer())),l=o.subarray(32,48),d=o.subarray(0,32),f=Zt(o).subarray(0,4),m=new N(N.DEFAULT_CAPACITY,N.LITTLE_ENDIAN);m.append(f),m.flip();const h=m.readUint32();if(i){if(h!==i)throw new Error("Invalid key");r=Ss(r,d,l)}else r=As(r,d,l);return{nonce:s,message:r,checksum:h}},Ss=(n,t,e)=>{let r=n;return r=Br(t,e).decrypt(r),r},As=(n,t,e)=>{let r=n;return r=Br(t,e).encrypt(r),r};let Ne=null;const Ls=()=>{if(Ne===null){const e=At.utils.randomSecretKey();Ne=Math.round(e[0]<<8|e[1])}let n=BigInt(Date.now());const t=++Ne%65535;return n=n<<BigInt(16)|BigInt(t),n},Tn=n=>{const t=Us(n,33);return new at(t)},Is=n=>n.readUint64(),$s=n=>n.readUint32(),Bs=n=>{const t=n.readVarint32(),e=n.copy(n.offset,n.offset+t);return n.skip(t),new Uint8Array(e.toBuffer())},ks=n=>t=>{const e={},r=new N(N.DEFAULT_CAPACITY,N.LITTLE_ENDIAN);r.append(t),r.flip();for(const[i,s]of n)try{e[i]=s(r)}catch(c){throw c.message=`${i}: ${c.message}`,c}return e};function Us(n,t){if(n){const e=n.copy(n.offset,n.offset+t);return n.skip(t),new Uint8Array(e.toBuffer())}else throw Error("No buffer found on first parameter")}const Ts=ks([["from",Tn],["to",Tn],["nonce",Is],["check",$s],["encrypted",Bs]]),Cs={Memo:Ts},Ur=(n,t,e,r)=>{if(!e.startsWith("#"))return e;e=e.substring(1),Cr(),n=Or(n),t=Os(t);const i=new N(N.DEFAULT_CAPACITY,N.LITTLE_ENDIAN);i.writeVString(e);const s=new Uint8Array(i.copy(0,i.offset).toBuffer()),{nonce:c,message:a,checksum:o}=xs(n,t,s,r),l=new N(N.DEFAULT_CAPACITY,N.LITTLE_ENDIAN);_r.Memo(l,{check:o,encrypted:a,from:n.createPublic(),nonce:c,to:t}),l.flip();const d=new Uint8Array(l.toBuffer());return"#"+re.encode(d)},Tr=(n,t)=>{if(!t.startsWith("#"))return t;t=t.substring(1),Cr(),n=Or(n);let e=Cs.Memo(re.decode(t));const{from:r,to:i,nonce:s,check:c,encrypted:a}=e,l=n.createPublic().toString()===new at(r.key).toString()?new at(i.key):new at(r.key);e=Es(n,l,s,a,c);const d=new N(N.DEFAULT_CAPACITY,N.LITTLE_ENDIAN);return d.append(e),d.flip(),"#"+d.readVString()};let be;const Cr=()=>{if(be===void 0){let n;be=!0;try{const t="5JdeC9P7Pbd1uGdFVEsJ41EkEnADbbHGq6p1BwFxm6txNBsQnsw",r=Ur(t,"STM8m5UgaFAAYQRuaNejYdS8FVLVp9Ss3K1qAVk5de6F8s3HnVbvA","#memo爱");n=Tr(t,r)}finally{be=n==="#memo爱"}}if(be===!1)throw new Error("This environment does not support encryption.")},Or=n=>typeof n=="string"?Et.fromString(n):n,Os=n=>typeof n=="string"?at.fromString(n):n,Rs={decode:Tr,encode:Ur};class Rr{timeout;constructor(t=1e4){this.timeout=t}async send(t,e){const r=new AbortController,i=setTimeout(()=>r.abort(),this.timeout);try{const s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),signal:r.signal});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);return await s.json()}finally{clearTimeout(i)}}}class Ds{endpoints;currentIndex=0;transport;requestId=1;constructor(t,e){this.endpoints=t??["https://api.hive.blog","https://api.deathwing.me","https://hive-api.arcange.eu"],this.transport=e??new Rr,ft.nodes=[this.endpoints[0]]}get currentEndpoint(){return this.endpoints[this.currentIndex]}setEndpoints(t){if(t.length===0)throw new Error("At least one endpoint required");this.endpoints=t,this.currentIndex=0,ft.nodes=[t[0]]}setTransport(t){this.transport=t}async call(t,e=[]){const r=this.endpoints.length;let i;for(let s=0;s<r;s++){const c=this.endpoints[(this.currentIndex+s)%this.endpoints.length],a={jsonrpc:"2.0",method:t,params:e,id:this.requestId++};try{const o=await this.transport.send(c,a);if(o.error)throw new Error(`RPC error ${o.error.code}: ${o.error.message}`);return this.currentIndex=(this.currentIndex+s)%this.endpoints.length,ft.nodes=[this.endpoints[this.currentIndex]],o.result}catch(o){i=o instanceof Error?o:new Error(String(o)),console.warn(`RPC call to ${c} failed: ${i.message}`)}}throw new Error(`All RPC endpoints failed. Last error: ${i?.message}`)}async healthCheck(){try{return await this.call("condenser_api.get_dynamic_global_properties"),!0}catch{return!1}}async getAccounts(t){return this.call("condenser_api.get_accounts",[t])}async getDynamicGlobalProperties(){return this.call("condenser_api.get_dynamic_global_properties")}async broadcastTransaction(t){return this.call("condenser_api.broadcast_transaction_synchronous",[t])}async getAccountHistory(t,e=-1,r=100){return this.call("condenser_api.get_account_history",[t,e,r])}}let qe;function Ht(){return qe||(qe=new Ds),qe}function ce(n){const t=Et.from(n),e=t.createPublic();return{private:t,public:e}}function Ns(n,t){const e=n.toString();return t.active.key_auths.some(([r])=>r===e)?"active":t.posting.key_auths.some(([r])=>r===e)?"posting":t.owner.key_auths.some(([r])=>r===e)?"owner":t.memo_key===e?"memo":null}async function Cn(n,t){const e=ce(n),i=await Ht().getAccounts([t]);if(i.length===0)throw new Error(`Account @${t} not found`);const s=i[0],c=Ns(e.public,s);if(!c)throw new Error(`Key does not match any authority on @${t}`);return{...e,role:c,account:s}}function Kt(n){const t=n.trim().split(" ");if(t.length!==2)throw new Error(`Invalid asset format: ${n}`);return{amount:parseFloat(t[0]),symbol:t[1]}}function Pt(n,t){return`${n.toFixed(3)} ${t}`}const On=["/api/comments","/api/search","/api/posts","/api/feed"];function qs(n){const t=new Uint8Array(n);return crypto.getRandomValues(t),Array.from(t,e=>e.toString(16).padStart(2,"0")).join("")}async function Hs(n){const e=new Blob([new TextEncoder().encode(n)]).stream().pipeThrough(new CompressionStream("gzip")).getReader(),r=[];for(;;){const{done:a,value:o}=await e.read();if(a)break;r.push(o)}const i=r.reduce((a,o)=>a+o.length,0),s=new Uint8Array(i);let c=0;for(const a of r)s.set(a,c),c+=a.length;return s}async function Ms(n){const e=new Blob([n]).stream().pipeThrough(new DecompressionStream("gzip")).getReader(),r=new TextDecoder;let i="";for(;;){const{done:s,value:c}=await e.read();if(s)break;i+=r.decode(c,{stream:!0})}return i+r.decode()}function Vs(n){let t="";for(let e=0;e<n.length;e++)t+=String.fromCharCode(n[e]);return btoa(t)}function zs(n){const t=atob(n),e=new Uint8Array(t.length);for(let r=0;r<t.length;r++)e[r]=t.charCodeAt(r);return e}async function Dr(n){const t=Vs(await Hs(JSON.stringify(n)));return{path:On[Math.floor(Math.random()*On.length)],body:JSON.stringify({q:t,sid:qs(8)}),headers:{"Content-Type":"application/json","X-Api-Version":"1"}}}async function Nr(n){const t=JSON.parse(n);if(!t.ok||!t.data?.r)throw new Error(t.error||"Invalid obfuscated response");return JSON.parse(await Ms(zs(t.data.r)))}class Ks{timeout;constructor(t=15e3){this.timeout=t}async send(t,e){const{path:r,body:i,headers:s}=await Dr(e),c=t.replace(/\/rpc\/?$/,"").replace(/\/+$/,"")+r,a=new AbortController,o=setTimeout(()=>a.abort(),this.timeout);try{const l=await fetch(c,{method:"POST",headers:s,body:i,signal:a.signal});if(!l.ok)throw new Error(`HTTP ${l.status}: ${l.statusText}`);return await Nr(await l.text())}finally{clearTimeout(o)}}}const Ps=2;function Fs(){return Ps>=2}const qr="propolis_obfuscation",ie=globalThis.fetch;let Le=!1;function an(){return localStorage.getItem(qr)==="direct"?"direct":"obfuscated"}function Wt(){return an()==="obfuscated"}function Ze(n){localStorage.setItem(qr,n),Hr()}function Hr(){const n=Ht();an()==="obfuscated"?(n.setTransport(new Ks),js()):(n.setTransport(new Rr),Zs())}function js(){Le||(Le=!0,globalThis.fetch=async function(n,t){if(!t?.body||typeof t.body!="string")return ie(n,t);let e;try{e=JSON.parse(t.body)}catch{return ie(n,t)}if(!e.jsonrpc)return ie(n,t);const r=await Dr(e),s=(typeof n=="string"?n:n instanceof URL?n.href:n.url).replace(/\/rpc\/?$/,"").replace(/\/+$/,""),c=await ie(s+r.path,{method:"POST",headers:r.headers,body:r.body,signal:t.signal});if(!c.ok)return c;const a=await Nr(await c.text());return new Response(JSON.stringify(a),{status:200,headers:{"Content-Type":"application/json"}})})}function Zs(){Le&&(Le=!1,globalThis.fetch=ie)}function ln(n,t){if(!n.startsWith("#"))return n;const e=Rs.decode(t,n);return e.startsWith("#")?e.slice(1):e}const Ws=["haa-service"];async function Ys(n,t,e=Ws,r=500){const i=Ht(),s=[],c=new Set(e.map(l=>l.toLowerCase())),a=Math.min(r,1e3),o=await i.getAccountHistory(n,-1,a);for(const[l,d]of o){const[f,m]=d.op;if(f!=="transfer")continue;const{from:h,to:b,memo:y}=m;if(b.toLowerCase()===n.toLowerCase()&&c.has(h.toLowerCase())&&!(!y||!y.startsWith("#")))try{const p=ln(y,t),_=JSON.parse(p);if(!Mr(_)||new Date(_.expires)<new Date)continue;s.push({payload:_,timestamp:d.timestamp,trxId:d.trx_id,from:h})}catch{continue}}return s.sort((l,d)=>new Date(d.timestamp).getTime()-new Date(l.timestamp).getTime()),s}async function Gs(n,t,e){const r=await Ys(n,t,e);return r.length>0?r[0].payload:null}function Mr(n){if(typeof n!="object"||n===null)return!1;const t=n;return typeof t.v=="number"&&Array.isArray(t.endpoints)&&t.endpoints.length>0&&t.endpoints.every(e=>typeof e=="string")&&typeof t.expires=="string"}const Js=["https://api.hive.blog","https://api.deathwing.me","https://hive-api.arcange.eu"],He="propolis_manual_endpoints";class Xs{endpoints=[];discoveryInterval=null;healthInterval=null;serviceAccounts;lastPayload=null;lastDiscoveryTime=0;discoveryAttempted=!1;constructor(t=["haa-service"]){this.serviceAccounts=t,this.loadManualEndpoints(),this.addFallbacks()}hasProxyEndpoints(){return this.endpoints.some(t=>t.source==="discovered"||t.source==="manual")}get allEndpoints(){return[...this.endpoints]}get healthyEndpoints(){const t={discovered:0,manual:1,fallback:2};return this.endpoints.filter(e=>e.healthy).sort((e,r)=>t[e.source]-t[r.source]).map(e=>e.url)}addManualEndpoint(t){this.endpoints.some(e=>e.url===t)||(this.endpoints.push({url:t,source:"manual",healthy:!0,lastCheck:0}),this.saveManualEndpoints(),this.applyToClient())}removeManualEndpoint(t){this.endpoints=this.endpoints.filter(e=>!(e.url===t&&e.source==="manual")),this.saveManualEndpoints(),this.applyToClient()}async discover(t,e){this.discoveryAttempted=!0;try{const r=await Gs(t,e,this.serviceAccounts);if(r){this.lastPayload=r,this.lastDiscoveryTime=Date.now(),this.endpoints=this.endpoints.filter(i=>i.source!=="discovered");for(const i of r.endpoints)this.endpoints.push({url:i,source:"discovered",healthy:!0,lastCheck:0});return this.applyToClient(),!0}return!1}catch(r){return console.warn("Endpoint discovery failed:",r),!1}}async healthCheckAll(){const e=(Wt()?this.endpoints.filter(r=>r.source!=="fallback"):this.endpoints).map(async r=>{try{const i=new AbortController,s=setTimeout(()=>i.abort(),8e3),c=await fetch(r.url,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",method:"condenser_api.get_dynamic_global_properties",params:[],id:1}),signal:i.signal});clearTimeout(s),r.healthy=c.ok}catch{r.healthy=!1}r.lastCheck=Date.now()});await Promise.allSettled(e),this.applyToClient()}startPeriodicChecks(t,e,r=30*6e4,i=5*6e4){this.stopPeriodicChecks(),this.discover(t,e),this.discoveryInterval=setInterval(()=>this.discover(t,e),r),setTimeout(()=>{this.healthCheckAll(),this.healthInterval=setInterval(()=>this.healthCheckAll(),i)},15e3)}stopPeriodicChecks(){this.discoveryInterval&&(clearInterval(this.discoveryInterval),this.discoveryInterval=null),this.healthInterval&&(clearInterval(this.healthInterval),this.healthInterval=null)}applyToClient(){const t={discovered:0,manual:1,fallback:2};let e=this.endpoints.filter(i=>i.healthy);Wt()&&(e=e.filter(i=>i.source!=="fallback"));const r=e.sort((i,s)=>t[i.source]-t[s.source]).map(i=>i.url);if(r.length>0)try{Ht().setEndpoints(r)}catch{}}loadManualEndpoints(){try{const t=localStorage.getItem(He);if(!t)return;const e=JSON.parse(t);for(const r of e)this.endpoints.some(i=>i.url===r)||this.endpoints.push({url:r,source:"manual",healthy:!0,lastCheck:0})}catch{}}saveManualEndpoints(){const t=this.endpoints.filter(e=>e.source==="manual").map(e=>e.url);t.length>0?localStorage.setItem(He,JSON.stringify(t)):localStorage.removeItem(He)}addFallbacks(){for(const t of Js)this.endpoints.some(e=>e.url===t)||this.endpoints.push({url:t,source:"fallback",healthy:!0,lastCheck:0})}}let Me;function Ft(){return Me||(Me=new Xs),Me}function it(n,...t){return t.reduce((e,r,i)=>e.replace(`%${i+1}`,String(r)),n)}const u={html_lang:"zh",app_title:"Propolis 钱包",nav_balance:"余额",nav_transfer:"转账",nav_savings:"储蓄",nav_settings:"设置",loading:"加载中…",amount:"金额",confirm:"确认",cancel:"取消",broadcasting:"广播中…",invalid_url:"无效的URL。",enter_proxy_url:"请输入代理URL。",amount_positive:"金额必须大于0。",username_placeholder:"用户名",key_placeholder:"5K...",proxy_placeholder:"https://proxy.example.com",rpc_placeholder:"https://proxy.example.com/rpc",confirm_direct_mode:"直连模式会暴露Hive流量,是否继续?",confirm_logout:"退出登录并清除密钥?",login_title:"登录",login_info:"输入您的Hive账户名和私有Active密钥。密钥绝不会离开此设备。",account_name:"账户名",private_active_key:"私有Active密钥",private_memo_key:"私有Memo密钥(可选)",memo_key_placeholder:"5K...(用于加密消息)",remember_keys:"记住密钥",remember_warning:"密钥将存储在本地存储中,仅在可信设备上使用。",login_btn:"登录",account_key_required:"需要账户名和Active密钥。",validating:"验证中…",wrong_key_role:"这是 %1 密钥,需要Active密钥。",wrong_memo_role:"第二个密钥是 %1,不是Memo密钥。",proxy_setup:"代理设置",proxy_required:"需要代理",proxy_desc_reconnect:"已启用混淆模式,但未配置代理节点。请输入代理URL以重新连接。",proxy_desc_connect:"已启用混淆模式。请输入代理节点URL以连接。",proxy_url:"代理URL",connect:"连接",switch_direct_link:"或切换到直连模式",paste_memo_prefix:"或从",block_explorer:"区块浏览器",paste_memo_suffix:"粘贴加密备忘录:",memo_textarea_placeholder:"#encrypted_memo...",decrypt_connect:"解密并连接",paste_memo_error:"请粘贴加密备忘录。",memo_key_required:"需要Memo密钥才能解密。",private_memo_key_label:"私有Memo密钥",memo_not_hash:"备忘录必须以#开头",memo_bad_json:"解密的备忘录不是有效的JSON。",memo_bad_payload:"备忘录不包含节点数据。",memo_expired:"节点数据已过期。",account_label:"账户",account_not_found:"未找到账户。",refresh:"刷新",hive:"HIVE",hbd:"HBD",hive_savings:"HIVE储蓄",hbd_savings:"HBD储蓄",est_interest:"预估利息(~20% APR):",hbd_yr:"HBD/年",pending_withdrawals:"%1 笔待处理提取",rpc_label:"RPC:",obfuscated:"已混淆",direct:"直连",send_transfer:"发送转账",recipient:"收款人",currency:"币种",memo_optional:"备注(可选)",public_memo:"公开备注",send:"发送",recipient_required:"需要收款人。",confirm_send:"发送 %1 给 @%2?",sent_tx:"已发送!TX: %1…(%2)",deposit_heading:"存入储蓄",withdraw_heading:"从储蓄提取",three_day_wait:"提取需要3天等待期。",deposit_btn:"存入储蓄",withdraw_btn:"从储蓄提取",pending_heading:"待处理",cancel_latest:"取消最新",available_hbd:"可用: %1 HBD",apr_estimate:"~%1 HBD/年(~20% APR)",n_pending:"%1 笔待处理",cancelled:"已取消。(%1)",confirm_deposit:"存入 %1?",confirm_withdraw:"提取(3天等待)%1?",deposited:"已存入",withdrawal_initiated:"提取已发起",not_found:"未找到。",privacy:"隐私",mode_label:"模式:",mode_obfuscated:"混淆",mode_direct:"直连",traffic_disguised:"流量伪装为普通网络请求。",traffic_plain:"明文JSON-RPC — 对网络观察者可见。",switch_to_direct:"切换到直连",switch_to_obfuscated:"切换到混淆",rpc_endpoint:"RPC节点",current_label:"当前:",custom_endpoint:"自定义节点",set_btn:"设置",reset_btn:"重置",check_btn:"检查",enter_url:"请输入URL。",added:"已添加。",reset_done:"已重置。",discovery:"节点发现",status_label:"状态:",n_found:"已找到 %1 个",none_found:"未找到",checking:"检查中…",expires_label:"过期时间:%1",discover:"发现",check_all:"全部检查",no_memo_key:"无Memo密钥 — 节点发现已禁用。",add_memo_hint:"在登录时添加Memo密钥以发现代理节点。",found_n:"找到 %1 个",none_found_dot:"未找到。",done:"完成。",endpoints:"节点列表",none:"无。",account_heading:"账户",active_check:"Active:",memo_check:"Memo:",persistent:"持久",session:"会话",logout:"退出",about:"关于",about_text:"Propolis钱包 v1.0.0 — 密钥绝不会离开此设备。"},G=(n,t)=>t.querySelector(n);function Qs(n,t){const e=n.trim();if(!e.startsWith("#"))throw new Error(u.memo_not_hash);const r=ln(e,t);let i;try{i=JSON.parse(r)}catch{throw new Error(u.memo_bad_json)}if(!Mr(i))throw new Error(u.memo_bad_payload);if(new Date(i.expires)<new Date)throw new Error(u.memo_expired);return i.endpoints}function Rn(n){return`<p class="sm mt mb">${u.paste_memo_prefix} <a href="https://hive.blog" target="_blank">${u.block_explorer}</a>${u.paste_memo_suffix}</p>
<textarea id="em" rows="3" placeholder="${u.memo_textarea_placeholder}" style="font-size:0.8rem"></textarea>
${n?"":`<label>${u.private_memo_key_label}</label><input type="password" id="mk" placeholder="${u.key_placeholder}" autocomplete="off">`}
<button class="btn-s" id="md">${u.decrypt_connect}</button>
<p class="err hidden" id="me"></p>`}function Dn(n,t,e){const r=G("#em",n),i=n.querySelector("#mk"),s=G("#md",n),c=G("#me",n),a=o=>{c.textContent=o,c.classList.remove("hidden")};s.addEventListener("click",()=>{const o=r.value.trim(),l=t||i?.value.trim()||"";if(!o){a(u.paste_memo_error);return}if(!l){a(u.memo_key_required);return}try{const d=Qs(o,l);e(d)}catch(d){a(d instanceof Error?d.message:String(d))}})}async function ve(n,t,e){const r=Wt(),i=Ft(),s=r&&!i.hasProxyEndpoints(),c=!!t.account;if(s&&c){const _=!!t.memoKeyWif;n.innerHTML=`<div class="card"><h2>${u.proxy_setup}</h2>
<p class="sm mt mb">${u.proxy_desc_reconnect}</p>
<label>${u.proxy_url}</label><input type="url" id="px" placeholder="${u.proxy_placeholder}" autocomplete="off">
<button class="btn-s" id="pa">${u.connect}</button>
${Rn(_)}
<p class="sm mt1"><a href="#" id="dm">${u.switch_direct_link}</a></p>
<p class="err hidden" id="pe"></p></div>`;const v=G("#px",n),S=G("#pa",n),L=G("#pe",n),I=G("#dm",n);S.addEventListener("click",()=>{const q=v.value.trim();if(!q){L.textContent=u.enter_proxy_url,L.classList.remove("hidden");return}try{new URL(q)}catch{L.textContent=u.invalid_url,L.classList.remove("hidden");return}i.addManualEndpoint(q),e.startDiscovery(),e.navigate("balance")}),Dn(n,t.memoKeyWif,q=>{for(const Q of q)i.addManualEndpoint(Q);e.startDiscovery(),e.navigate("balance")}),I.addEventListener("click",q=>{q.preventDefault(),confirm(u.confirm_direct_mode)&&(Ze("direct"),e.startDiscovery(),e.navigate("balance"))});return}n.innerHTML=`<div class="card"><h2>${u.login_title}</h2>
${s?`<div class="info mb"><p class="sm"><strong>${u.proxy_required}</strong> — ${u.proxy_desc_connect}</p>
<label>${u.proxy_url}</label><input type="url" id="px" placeholder="${u.proxy_placeholder}" autocomplete="off">
<button class="btn-s" id="pa">${u.connect}</button>
${Rn(!1)}
<p class="sm mt1"><a href="#" id="dm">${u.switch_direct_link}</a></p>
<p class="err hidden" id="pe"></p></div>`:""}
<p class="sm mt mb">${u.login_info}</p>
<label>${u.account_name}</label><input id="a" placeholder="${u.username_placeholder}" autocomplete="off" spellcheck="false">
<label>${u.private_active_key}</label><input type="password" id="k" placeholder="${u.key_placeholder}" autocomplete="off">
<label>${u.private_memo_key}</label><input type="password" id="m" placeholder="${u.memo_key_placeholder}" autocomplete="off">
<div class="mb"><label class="fx" style="cursor:pointer"><input type="checkbox" id="p" style="width:auto;margin:0"><span class="sm">${u.remember_keys}</span></label>
<p class="wrn hidden" id="pw">${u.remember_warning}</p></div>
<button id="b"${s?" disabled":""}>${u.login_btn}</button><p class="err hidden" id="e"></p><p class="ok hidden" id="s"></p></div>`;const a=G("#a",n),o=G("#k",n),l=G("#m",n),d=G("#p",n),f=G("#pw",n),m=G("#b",n),h=G("#e",n),b=G("#s",n),y=(_,v)=>{_.textContent=v,_.classList.remove("hidden")},p=(..._)=>_.forEach(v=>v.classList.add("hidden"));if(s){const _=G("#px",n),v=G("#pa",n),S=G("#pe",n),L=G("#dm",n);v.addEventListener("click",()=>{const I=_.value.trim();if(!I){y(S,u.enter_proxy_url);return}try{new URL(I)}catch{y(S,u.invalid_url);return}i.addManualEndpoint(I),ve(n,t,e)}),Dn(n,null,I=>{for(const q of I)i.addManualEndpoint(q);ve(n,t,e)}),L.addEventListener("click",I=>{I.preventDefault(),confirm(u.confirm_direct_mode)&&(Ze("direct"),ve(n,t,e))})}d.addEventListener("change",()=>f.classList.toggle("hidden",!d.checked)),m.addEventListener("click",async()=>{const _=a.value.trim().toLowerCase().replace("@",""),v=o.value.trim(),S=l.value.trim()||null;if(!_||!v){y(h,u.account_key_required);return}m.disabled=!0,p(h),y(b,u.validating);try{const L=await Cn(v,_);if(L.role!=="active"&&L.role!=="owner"){y(h,it(u.wrong_key_role,L.role)),p(b),m.disabled=!1;return}if(S){const I=await Cn(S,_);if(I.role!=="memo"){y(h,it(u.wrong_memo_role,I.role)),p(b),m.disabled=!1;return}}t.account=_,t.activeKeyWif=v,t.memoKeyWif=S,t.persistKeys=d.checked,e.saveState(),e.startDiscovery(),e.navigate("balance")}catch(L){y(h,L instanceof Error?L.message:String(L)),p(b),m.disabled=!1}})}async function to(n,t,e){n.innerHTML=`<div class="card"><p class="bl">${u.account_label}</p>
<p style="font-size:1.1rem;font-weight:bold" class="mb">@${t.account}</p>
<div id="b"><p class="mt">${u.loading}</p></div></div>
<button class="btn-s" id="r">${u.refresh}</button>`;const r=n.querySelector("#b"),i=n.querySelector("#r");async function s(){r.innerHTML=`<p class="mt">${u.loading}</p>`,i.disabled=!0;try{const c=Ht(),a=await c.getAccounts([t.account]);if(!a.length){r.innerHTML=`<p class="err">${u.account_not_found}</p>`;return}const o=a[0],l=Kt(o.balance),d=Kt(o.hbd_balance),f=Kt(o.savings_balance),m=Kt(o.savings_hbd_balance);r.innerHTML=`<div class="g2">
<div><p class="bl">${u.hive}</p><p class="ba">${l.amount.toFixed(3)}</p></div>
<div><p class="bl">${u.hbd}</p><p class="ba">${d.amount.toFixed(3)}</p></div>
<div><p class="bl">${u.hive_savings}</p><p class="ba">${f.amount.toFixed(3)}</p></div>
<div><p class="bl">${u.hbd_savings}</p><p class="ba gc">${m.amount.toFixed(3)}</p></div></div>
${m.amount>0?`<div class="info mt2"><p class="sm mt">${u.est_interest} <strong class="gc">~${(m.amount*.2).toFixed(3)} ${u.hbd_yr}</strong></p></div>`:""}
${o.savings_withdraw_requests>0?`<p class="wrn mt1">${it(u.pending_withdrawals,o.savings_withdraw_requests)}</p>`:""}
<p class="xs mt mt2">${u.rpc_label} ${c.currentEndpoint}${(()=>{const b=Ft().allEndpoints.find(y=>y.url===c.currentEndpoint);return b?` (${b.source})`:""})()}${Fs()?` | ${Wt()?`<span class="gc">${u.obfuscated}</span>`:`<span class="wrn">${u.direct}</span>`}`:""}</p>`}catch(c){r.innerHTML=`<p class="err">${c instanceof Error?c.message:c}</p>`}finally{i.disabled=!1}}i.addEventListener("click",s),await s()}function eo(n,t,e,r=""){return["transfer",{from:n,to:t,amount:e,memo:r}]}function no(n,t,e,r=""){return["transfer_to_savings",{from:n,to:t,amount:e,memo:r}]}function ro(n,t,e,r,i=""){return["transfer_from_savings",{from:n,request_id:t,to:e,amount:r,memo:i}]}function io(n,t){return["cancel_transfer_from_savings",{from:n,request_id:t}]}async function Ie(n,t){const e=new sn;for(const[i,s]of n)await e.addOperation(i,s);return e.sign(t.private),await e.broadcast(!0)}async function so(n,t,e){n.innerHTML=`<div class="card"><h2>${u.send_transfer}</h2>
<label>${u.recipient}</label><input id="to" placeholder="${u.username_placeholder}" autocomplete="off" spellcheck="false">
<label>${u.amount}</label><input type="number" id="am" placeholder="0.000" step="0.001" min="0.001">
<label>${u.currency}</label><select id="cu"><option value="HBD">${u.hbd}</option><option value="HIVE">${u.hive}</option></select>
<label>${u.memo_optional}</label><input id="me" placeholder="${u.public_memo}" autocomplete="off">
<div id="cb" class="hidden mb"><div class="card" style="background:var(--bg);border-color:var(--wn)">
<p class="sm" id="ct"></p><div class="fx mt2"><button class="btn-ok" id="y">${u.confirm}</button><button class="btn-s" id="n">${u.cancel}</button></div></div></div>
<button id="s">${u.send}</button><p class="err hidden" id="e"></p><p class="ok hidden" id="o"></p></div>`;const r=n.querySelector("#to"),i=n.querySelector("#am"),s=n.querySelector("#cu"),c=n.querySelector("#me"),a=n.querySelector("#s"),o=n.querySelector("#cb"),l=n.querySelector("#ct"),d=n.querySelector("#y"),f=n.querySelector("#n"),m=n.querySelector("#e"),h=n.querySelector("#o"),b=(p,_)=>{p.textContent=_,p.classList.remove("hidden")},y=(...p)=>p.forEach(_=>_.classList.add("hidden"));a.addEventListener("click",()=>{const p=r.value.trim().toLowerCase().replace("@",""),_=parseFloat(i.value);if(y(m,h),!p){b(m,u.recipient_required);return}if(!_||_<=0){b(m,u.amount_positive);return}l.textContent=it(u.confirm_send,Pt(_,s.value),p),o.classList.remove("hidden"),a.classList.add("hidden")}),f.addEventListener("click",()=>{o.classList.add("hidden"),a.classList.remove("hidden")}),d.addEventListener("click",async()=>{const p=r.value.trim().toLowerCase().replace("@",""),_=parseFloat(i.value),v=s.value;d.disabled=!0,d.textContent=u.broadcasting,y(m);try{const S=ce(t.activeKeyWif),L=await Ie([eo(t.account,p,Pt(_,v),c.value)],S);o.classList.add("hidden"),a.classList.remove("hidden"),b(h,it(u.sent_tx,L.tx_id?.slice(0,12)||"",L.status)),r.value="",i.value="",c.value=""}catch(S){b(m,S instanceof Error?S.message:String(S)),o.classList.add("hidden"),a.classList.remove("hidden")}finally{d.disabled=!1,d.textContent=u.confirm}})}async function oo(n,t,e){n.innerHTML=`<div id="si" class="card"><p class="mt">${u.loading}</p></div>
<div class="card"><h2>${u.deposit_heading}</h2><label>${u.amount}</label>
<input type="number" id="da" placeholder="0.000" step="0.001" min="0.001">
<select id="dc"><option value="HBD">${u.hbd}</option><option value="HIVE">${u.hive}</option></select>
<button id="db">${u.deposit_btn}</button></div>
<div class="card"><h2>${u.withdraw_heading}</h2><p class="sm mt mb">${u.three_day_wait}</p>
<label>${u.amount}</label><input type="number" id="wa" placeholder="0.000" step="0.001" min="0.001">
<select id="wc"><option value="HBD">${u.hbd}</option><option value="HIVE">${u.hive}</option></select>
<button id="wb">${u.withdraw_btn}</button></div>
<div id="pw" class="card hidden"><h2>${u.pending_heading}</h2><div id="pl"></div></div>
<p class="err hidden" id="e"></p><p class="ok hidden" id="o"></p>`;const r=n.querySelector("#si"),i=n.querySelector("#da"),s=n.querySelector("#dc"),c=n.querySelector("#db"),a=n.querySelector("#wa"),o=n.querySelector("#wc"),l=n.querySelector("#wb"),d=n.querySelector("#pw"),f=n.querySelector("#pl"),m=n.querySelector("#e"),h=n.querySelector("#o"),b=v=>{m.textContent=v,m.classList.remove("hidden"),h.classList.add("hidden")},y=v=>{h.textContent=v,h.classList.remove("hidden"),m.classList.add("hidden")};async function p(){try{const v=(await Ht().getAccounts([t.account]))[0];if(!v){r.innerHTML=`<p class="err">${u.not_found}</p>`;return}const S=Kt(v.savings_hbd_balance),L=Kt(v.savings_balance),I=Kt(v.hbd_balance);r.innerHTML=`<div class="g2">
<div><p class="bl">${u.hbd_savings}</p><p class="ba gc">${S.amount.toFixed(3)}</p></div>
<div><p class="bl">${u.hive_savings}</p><p class="ba">${L.amount.toFixed(3)}</p></div></div>
<p class="sm mt mt1">${it(u.available_hbd,I.amount.toFixed(3))}</p>
${S.amount>0?`<p class="sm gc mt1">${it(u.apr_estimate,(S.amount*.2).toFixed(3))}</p>`:""}`,v.savings_withdraw_requests>0?(d.classList.remove("hidden"),f.innerHTML=`<p class="wrn">${it(u.n_pending,v.savings_withdraw_requests)}</p>
<button class="btn-s mt1" id="cb">${u.cancel_latest}</button>`,f.querySelector("#cb").addEventListener("click",async function(){this.disabled=!0;try{const q=await Ie([io(t.account,0)],ce(t.activeKeyWif));y(it(u.cancelled,q.status)),await p()}catch(q){b(q instanceof Error?q.message:String(q))}finally{this.disabled=!1}})):d.classList.add("hidden")}catch(v){r.innerHTML=`<p class="err">${v instanceof Error?v.message:v}</p>`}}async function _(v,S,L,I){const q=parseFloat(S.value),Q=L.value;if(!q||q<=0){b(u.amount_positive);return}const W=it(I?u.confirm_deposit:u.confirm_withdraw,Pt(q,Q));if(confirm(W)){v.disabled=!0,v.textContent=u.broadcasting;try{const C=ce(t.activeKeyWif),dt=I?no(t.account,t.account,Pt(q,Q)):ro(t.account,Math.floor(Date.now()/1e3)%2147483647,t.account,Pt(q,Q)),ot=await Ie([dt],C);y(`${I?u.deposited:u.withdrawal_initiated}. (${ot.status})`),S.value="",await p()}catch(C){b(C instanceof Error?C.message:String(C))}finally{v.disabled=!1,v.textContent=I?u.deposit_btn:u.withdraw_btn}}}c.addEventListener("click",()=>_(c,i,s,!0)),l.addEventListener("click",()=>_(l,a,o,!1)),await p()}const co=["https://api.hive.blog","https://api.deathwing.me","https://hive-api.arcange.eu"];async function Vr(n,t,e){const r=Ht(),i=Ft(),s=i.allEndpoints.filter(p=>p.source==="discovered"),c=s.length>0,a=!!t.memoKeyWif,o=Wt(),l=(p,_)=>`<p class="sm ${p}">${_}</p>`;n.innerHTML=`${`<div class="card"><h2>${u.privacy}</h2>
${l("mt",`${u.mode_label} <strong class="${o?"gc":"wrn"}">${o?u.mode_obfuscated:u.mode_direct}</strong>`)}
${l("mt1",o?u.traffic_disguised:u.traffic_plain)}
<button class="btn-s mt1" id="ot">${o?u.switch_to_direct:u.switch_to_obfuscated}</button>
<p class="sm hidden mt1" id="os"></p></div>`}
<div class="card"><h2>${u.rpc_endpoint}</h2>
${l("mt mb",`${u.current_label} <code id="ce">${r.currentEndpoint}</code>`)}
<label>${u.custom_endpoint}</label><input type="url" id="ci" placeholder="${u.rpc_placeholder}">
<button class="btn-s" id="se">${u.set_btn}</button><button class="btn-s" id="re">${u.reset_btn}</button><button class="btn-s" id="hc">${u.check_btn}</button>
<p class="sm hidden" id="es"></p></div>
${`<div class="card"><h2>${u.discovery}</h2>
${a?`${l("mt",`${u.status_label} <strong class="${c?"gc":""}">${c?it(u.n_found,s.length):i.discoveryAttempted?u.none_found:u.checking}</strong>`)}
${c?`<div class="mt1">${s.map(p=>l("",`<code>${p.url}</code> ${p.healthy?'<span class="gc">✓</span>':'<span class="err">✗</span>'}`)).join("")}</div>`:""}
${i.lastPayload?l("mt1",it(u.expires_label,new Date(i.lastPayload.expires).toLocaleDateString())):""}
<button class="btn-s mt1" id="rd">${u.discover}</button><button class="btn-s" id="ha">${u.check_all}</button>`:`${l("mt wrn",u.no_memo_key)}${l("",u.add_memo_hint)}`}
<p class="sm hidden mt1" id="ds"></p></div>`}
${`<div class="card"><h2>${u.endpoints}</h2><div id="el">${ye(i)}</div></div>`}
<div class="card"><h2>${u.account_heading}</h2>
${l("",`@<strong>${t.account}</strong>`)}
${l("mt mb",`${u.active_check} ${t.activeKeyWif?"✓":"✗"} | ${u.memo_check} ${t.memoKeyWif?"✓":"✗"} | ${t.persistKeys?u.persistent:u.session}`)}
<button class="btn-er" id="lo">${u.logout}</button></div>
<div class="card"><h2>${u.about}</h2>${l("mt",u.about_text)}</div>`;const d=n.querySelector("#ci"),f=n.querySelector("#ce"),m=n.querySelector("#es"),h=n.querySelector("#ds"),b=n.querySelector("#el"),y=(p,_,v)=>{p.className=`sm ${_}`,p.textContent=v,p.classList.remove("hidden")};n.querySelector("#ot").addEventListener("click",()=>{const p=an()==="obfuscated"?"direct":"obfuscated";p==="direct"&&!confirm(u.confirm_direct_mode)||(Ze(p),Vr(n,t,e))}),n.querySelector("#se").addEventListener("click",()=>{const p=d.value.trim();if(!p){y(m,"err",u.enter_url);return}try{new URL(p),i.addManualEndpoint(p),f.textContent=r.currentEndpoint,y(m,"ok",u.added),d.value="",b&&(b.innerHTML=ye(i))}catch{y(m,"err",u.invalid_url)}}),n.querySelector("#re").addEventListener("click",()=>{r.setEndpoints(co),f.textContent=r.currentEndpoint,y(m,"ok",u.reset_done)}),n.querySelector("#hc").addEventListener("click",async function(){this.disabled=!0,y(m,"mt","...");const p=await r.healthCheck();y(m,p?"ok":"err",p?"✓ OK":"✗ Failed"),this.disabled=!1}),n.querySelector("#rd")?.addEventListener("click",async function(){this.disabled=!0,y(h,"mt1","...");const p=await i.discover(t.account,t.memoKeyWif);y(h,p?"ok":"wrn",p?it(u.found_n,i.lastPayload.endpoints.length):u.none_found_dot),f.textContent=r.currentEndpoint,b.innerHTML=ye(i),this.disabled=!1}),n.querySelector("#ha")?.addEventListener("click",async function(){this.disabled=!0,y(h,"mt1","..."),await i.healthCheckAll(),y(h,"ok",u.done),f.textContent=r.currentEndpoint,b.innerHTML=ye(i),this.disabled=!1}),n.querySelector("#lo").addEventListener("click",()=>{confirm(u.confirm_logout)&&e.logout()})}function ye(n){const t=n.allEndpoints;return t.length?t.map(e=>`<p class="sm"><code>${e.url}</code> <span class="xs">[${e.source}]</span> ${e.healthy?'<span class="gc">✓</span>':'<span class="err">✗</span>'}</p>`).join(""):`<p class="sm">${u.none}</p>`}const ao={login:ve,balance:to,transfer:so,savings:oo,settings:Vr},lo=[{hash:"balance",label:u.nav_balance},{hash:"transfer",label:u.nav_transfer},{hash:"savings",label:u.nav_savings},{hash:"settings",label:u.nav_settings}];class uo{container;navEl;contentEl;state;constructor(t){this.container=t,this.state=this.loadState(),Hr(),this.container.innerHTML="";const e=document.createElement("div");e.className="ct",document.documentElement.lang=u.html_lang,document.title=u.app_title,e.innerHTML=`<h1>${u.app_title}</h1>`,this.navEl=document.createElement("nav"),this.contentEl=document.createElement("div"),this.contentEl.className="ct",e.appendChild(this.navEl),this.container.appendChild(e),this.container.appendChild(this.contentEl),this.renderNav(),window.addEventListener("hashchange",()=>this.route()),this.route(),(!Wt()||Ft().hasProxyEndpoints())&&this.startDiscovery()}loadState(){const t=localStorage.getItem("haa_keys");if(t)try{const s=JSON.parse(t);return{account:s.account||null,activeKeyWif:s.activeKeyWif||null,memoKeyWif:s.memoKeyWif||null,persistKeys:!0}}catch{}const e=sessionStorage.getItem("haa_account"),r=sessionStorage.getItem("haa_activeKey"),i=sessionStorage.getItem("haa_memoKey");return{account:e,activeKeyWif:r,memoKeyWif:i,persistKeys:!1}}saveState(){this.state.persistKeys?localStorage.setItem("haa_keys",JSON.stringify({account:this.state.account,activeKeyWif:this.state.activeKeyWif,memoKeyWif:this.state.memoKeyWif})):(localStorage.removeItem("haa_keys"),this.state.account&&sessionStorage.setItem("haa_account",this.state.account),this.state.activeKeyWif&&sessionStorage.setItem("haa_activeKey",this.state.activeKeyWif),this.state.memoKeyWif&&sessionStorage.setItem("haa_memoKey",this.state.memoKeyWif))}startDiscovery(){this.state.account&&this.state.memoKeyWif&&Ft().startPeriodicChecks(this.state.account,this.state.memoKeyWif)}logout(){Ft().stopPeriodicChecks(),this.state.account=null,this.state.activeKeyWif=null,this.state.memoKeyWif=null,localStorage.removeItem("haa_keys"),sessionStorage.clear(),this.navigate("login")}navigate(t){window.location.hash=`#${t}`}renderNav(){if(this.navEl.innerHTML="",!this.state.account){this.navEl.classList.add("hidden");return}this.navEl.classList.remove("hidden");const t=(window.location.hash||"#balance").slice(1);for(const e of lo){const r=document.createElement("a");r.href=`#${e.hash}`,r.textContent=e.label,e.hash===t&&(r.className="active"),this.navEl.appendChild(r)}}route(){const t=(window.location.hash||"").slice(1)||"login",e=Wt()&&!Ft().hasProxyEndpoints();if(e&&t!=="login"){this.navigate("login");return}if(t!=="login"&&!this.state.account){this.navigate("login");return}if(t==="login"&&this.state.account&&!e){this.navigate("balance");return}const r=ao[t];if(!r){this.navigate("balance");return}this.renderNav(),this.contentEl.innerHTML="",r(this.contentEl,this.state,this)}}const fo=document.getElementById("app"),ho=new uo(fo);window.propolis={app:ho,getClient:Ht,importKey:ce,formatAsset:Pt,signAndBroadcast:Ie,decryptMemo:ln};</script>
  <style rel="stylesheet" crossorigin>*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}:root{--bg:#1a1a2e;--sf:#16213e;--in:#0f3460;--tx:#e8e8e8;--tm:#a0a0b0;--ac:#e94560;--ah:#ff6b81;--ok:#4ecca3;--wn:#f0c040;--er:#e94560;--bd:#2a2a4a;--r:8px}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--tx);min-height:100vh;line-height:1.5}.ct{max-width:480px;margin:0 auto;padding:24px 16px}h1{font-size:1.5rem;margin-bottom:8px}h2{font-size:1.2rem;margin-bottom:12px}p{margin-bottom:8px}button{background:var(--ac);color:var(--tx);border:none;padding:10px 20px;border-radius:var(--r);cursor:pointer;font-size:1rem;width:100%;margin-bottom:8px}button:hover{background:var(--ah)}button:disabled{opacity:.5;cursor:not-allowed}.btn-s{background:var(--sf);border:1px solid var(--bd)}.btn-ok{background:var(--ok)}.btn-er{background:var(--er)}input,textarea,select{background:var(--in);color:var(--tx);border:1px solid var(--bd);padding:10px 12px;border-radius:var(--r);font-size:1rem;width:100%;margin-bottom:12px}input:focus,textarea:focus,select:focus{outline:none;border-color:var(--ac)}label{display:block;font-size:.85rem;color:var(--tm);margin-bottom:4px}.card{background:var(--sf);border:1px solid var(--bd);border-radius:var(--r);padding:16px;margin-bottom:12px}.ba{font-size:1.8rem;font-weight:700}.bl{font-size:.85rem;color:var(--tm)}.sm{font-size:.85rem}.xs{font-size:.75rem}.err{color:var(--er);font-size:.85rem}.ok{color:var(--ok);font-size:.85rem}.wrn{color:var(--wn);font-size:.85rem}.mt{color:var(--tm)}.gc{color:var(--ok)}.g2{display:grid;grid-template-columns:1fr 1fr;gap:12px}.mb{margin-bottom:12px}.mt1{margin-top:8px}.mt2{margin-top:12px}.info{padding:8px;background:var(--in);border-radius:var(--r)}.fx{display:flex;gap:8px}nav{display:flex;gap:4px;mar