memoscan
← all memos

Memo 0xf5c4519e…e193ba on Ethereum

0xacfba7ce…4082·#25,751,346·view on Etherscan
atUnits(v,dec); const pretty=n>=1?n.toLocaleString("en-US",{maximumFractionDigits:4}):n.toPrecision(4); el.innerHTML=`Balance: ${pretty} <a href="#" title="Use maximum (leaves gas for ETH)">Max</a>`}; async function refreshBalance(){ const f=TOKENS[fromSel.value]; if(!account||!f){bal.textContent="";fromBalance=0n;render();return} const my=++bSeq; try{ const v=await readBal(f); if(my!==bSeq)return; fromBalance=v;showBal(bal,v,f.dec); }catch{if(my===bSeq){bal.textContent="";fromBalance=0n}} refreshBalance1(); render(); } let toBalance=0n,b1Seq=0; async function refreshBalance1(){ const t=TOKENS[toSel.value]; bal1.classList.toggle("hide",!lqMode); if(!lqMode||!account||!t){bal1.textContent="";toBalance=0n;return} const my=++b1Seq; try{ const v=await readBal(t); if(my!==b1Seq)return; toBalance=v;showBal(bal1,v,t.dec); }catch{if(my===b1Seq){bal1.textContent="";toBalance=0n}} } const optsHtml=()=>{ let ft="",nft=""; TOKENS.forEach((t,i)=>{const o=`<option value="${i}">${t.sym}</option>`; if(t.std==="nft")nft+=o;else ft+=o}); return ft +(nft?`<optgroup label="NFT collections — auction only">${nft}</optgroup>`:"") +`<option value="__custom">+ Custom token…</option>`; }; const rebuild=()=>{for(const s of[fromSel,toSel]){const v=s.value;s.innerHTML=optsHtml();s.value=v}}; const pairAddrs=()=>({fa:TOKENS[fromSel.value]?.addr,ta:TOKENS[toSel.value]?.addr, fi:String(fromSel.value),ti:String(toSel.value)}); const restorePair=k=>{ if(!k)return; const at=a=>a?TOKENS.findIndex(t=>t.addr.toLowerCase()===a.toLowerCase()):-1; const held=(cur,want)=>String(cur)===want||!TOKENS[cur]; if(held(fromSel.value,k.fi)){const i=at(k.fa);if(i>=0)fromSel.value=i} if(held(toSel.value,k.ti)){const i=at(k.ta);if(i>=0&&String(i)!==String(fromSel.value))toSel.value=i} for(const s of[fromSel,toSel]){ const want=s.dataset.addr; if(!want||held(s.value,s===fromSel?k.fi:k.ti))continue; const i=at(want); if(i>=0&&(s===fromSel||String(i)!==String(fromSel.value)))s.value=i; } }; const isNft=v=>TOKENS[v]?.std==="nft"; let pairChosen=false; const wrapTwin=(a,b)=>{ const x=(a||"").toLowerCase(),y=(b||"").toLowerCase(),w=WETH.toLowerCase(); return (x===ZERO&&y===w)||(x===w&&y===ZERO); }; const rankedOutputs=fi=>TOKENS.map((t,i)=>i) .filter(i=>i!==fi&&!isNft(String(i))&&!wrapTwin(TOKENS[i].addr,TOKENS[fi]?.addr)); const deadOutputs=new Set(); let pairAuto=false; const rankedDefaults=()=>{ if(TOKENS.length<2)return; const fi=TOKENS.findIndex((t,i)=>!isNft(String(i))); if(fi<0)return; const ti=rankedOutputs(fi).find(i=>!deadOutputs.has(TOKENS[i].addr.toLowerCase())); if(ti==null)return; fromSel.value=String(fi);toSel.value=String(ti); fromSel.dataset.prev=fromSel.value;toSel.dataset.prev=toSel.value; pairAuto=true; try{LS["zswap:pair"]=JSON.stringify([TOKENS[fi].addr,TOKENS[ti].addr])}catch{} }; const advancePastDeadPair=()=>{ if(!pairAuto||pairChosen)return false; const cur=TOKENS[toSel.value]; if(!cur)return false; deadOutputs.add(cur.addr.toLowerCase()); const fi=Number(fromSel.value); const next=rankedOutputs(fi).find(i=>!deadOutputs.has(TOKENS[i].addr.toLowerCase())); if(next==null)return false; toSel.value=String(next);toSel.dataset.prev=toSel.value; syncDisabled();syncIcons(); return true; }; const settlePair=keep=>{if(pairChosen)restorePair(keep);else rankedDefaults()}; const adoptList=keep=>{ rebuild(); settlePair(keep); if(!TOKENS[fromSel.value])fromSel.value=0; if(!TOKENS[toSel.value]||toSel.value===fromSel.value)toSel.value=TOKENS[1]?1:0; syncDisabled();syncIcons(); }; const syncDisabled=keep=>{ const pair=tab!=="send"; const nftOk=tab==="book"; if(pair&&fromSel.value===toSel.value){ const alt=TOKENS.findIndex((t,i)=>String(i)!==fromSel.value&&(nftOk||t.std!=="nft")); if(alt>=0){toSel.value=String(alt);toSel.dataset.prev=toSel.value} } if(pair&&nftOk&&isNft(fromSel.value)&&isNft(toSel.value)){ const give=keep===toSel?fromSel:toSel,stay=give===fromSel?toSel:fromSel; const alt=TOKENS.findIndex((t,i)=>t.std!=="nft"&&String(i)!==stay.value); if(alt>=0){give.value=String(alt);give.dataset.prev=give.value} } for(const[sel,other]of[[fromSel,toSel],[toSel,fromSel]]) for(const opt of sel.options) opt.disabled=opt.value!=="__custom"&&((pair&&opt.value===other.value)||(!nftOk&&isNft(opt.value))); }; fromSel.innerHTML=optsHtml();fromSel.value=0; toSel.innerHTML=optsHtml(); const LAST_PAIR="zswap:pair"; const seatPair=()=>{ try{ const [a,b]=JSON.parse(LS[LAST_PAIR]||"[]"); const fi=TOKENS.findIndex(t=>t.addr.toLowerCase()===String(a).toLowerCase()); const ti=TOKENS.findIndex(t=>t.addr.toLowerCase()===String(b).toLowerCase()); if(fi>=0&&ti>=0&&fi!==ti){fromSel.value=String(fi);toSel.value=String(ti);return true} }catch{} return false; }; if(!seatPair())toSel.value=String(Math.max(1,TOKENS.findIndex(t=>t.sym==="USDC"))); syncDisabled(); const iconShown=["",""]; const syncIcons=()=>{ [[fromIcon,fromSel],[toIcon,toSel]].forEach(([el,s],i)=>{ const t=TOKENS[s.value],ic=t?.icon||""; if(iconShown[i]!==ic){iconShown[i]=ic;el.innerHTML=ic} if(t)s.dataset.addr=t.addr}); syncPickers()}; const tkPanel=document.getElementById("tkPanel"),tkFind=document.getElementById("tkFind"), tkList=document.getElementById("tkList"); let tkSel=null,tkCur=-1; const pickBtn=sel=>document.getElementById(sel===fromSel?"fromPick":"toPick"); const syncPickers=()=>{ for(const sel of [fromSel,toSel]){ const b=pickBtn(sel);if(!b)continue; const t=TOKENS[sel.value]; b.classList.add("on");sel.classList.add("rich"); b.querySelector(".tkbs").textContent=t?t.sym:(sel.selectedOptions[0]?.textContent||""); b.setAttribute("aria-label",`Token: ${t?t.sym:"none"} - change`); const pill=b.closest(".pill"); if(pill){ const name=t?.name&&t.name.toLowerCase()!==t.sym.toLowerCase()?t.name:""; const extra=[name,t?.desc].filter(Boolean); if(extra.length)pill.title=[`${t.sym}${name?" — "+name:""}`,t.desc].filter(Boolean).join("\n\n"); else pill.removeAttribute("title"); } } }; const tkRows=()=>{ const q=tkFind.value.trim().toLowerCase(); tkList.textContent=""; const frag=document.createDocumentFragment(); let n=0,group=""; for(const opt of tkSel.options){ const t=TOKENS[opt.value]; if(q){ const hay=[opt.textContent,t?.name,t?.addr].filter(Boolean).join(" ").toLowerCase(); if(!hay.includes(q))continue; } const g=opt.parentElement?.label||""; if(g&&g!==group){const h=document.createElement("div");h.className="tkg";h.textContent=g;frag.appendChild(h);group=g} const r=document.createElement("button"); r.type="button";r.className="tkr";r.setAttribute("role","option"); r.dataset.value=opt.value; r.setAttribute("aria-selected",String(opt.value===tkSel.value)); if(opt.disabled)r.setAttribute("aria-disabled","true"); const ic=document.createElement("span");ic.className="tki"; if(t?.icon)ic.innerHTML=t.icon; r.appendChild(ic); const tx=document.createElement("span");tx.className="tkt"; const top=document.createElement("span");top.className="tks"; const b=document.createElement("b");b.textContent=opt.textContent.trim();top.appendChild(b); if(t?.name&&t.name.toLowerCase()!==b.textContent.toLowerCase()){ const nm=document.createElement("span");nm.className="tkn";nm.textContent=t.name;top.appendChild(nm); } tx.appendChild(top); if(t?.desc){const d=document.createElement("span");d.className="tkd";d.textContent=t.desc;tx.appendChild(d)} r.appendChild(tx); if(opt.value===tkSel.value){const m=document.createElement("span");m.className="tkmark";m.textContent="✓";r.appendChild(m)} frag.appendChild(r);n++; } if(!n){const e=document.createElement("div");e.className="tkempty";e.textContent="No token matches that.";frag.appendChild(e)} tkList.appendChild(frag); tkCur=-1; }; const tkOpen=sel=>{ if(tkSel&&tkSel!==sel)pickBtn(tkSel)?.setAttribute("aria-expanded","false"); tkSel=sel;tkFind.value="";tkRows(); tkPanel.classList.remove("hide"); if(matchMedia("(pointer:coarse)").matches){ tkPanel.style.left=tkPanel.style.top=tkPanel.style.maxHeight=tkPanel.style.width=""; pickBtn(sel).setAttribute("aria-expanded","true"); tkFind.focus(); return; } const b=pickBtn(sel).getBoundingClientRect(); const card=document.querySelector(".card").getBoundingClientRect(); const w=Math.min(Math.max(card.width,240),innerWidth-16); tkPanel.style.width=w+"px"; const left=Math.max(8,Math.min(card.left+scrollX,scrollX+innerWidth-w-8)); const above=b.top,below=innerHeight-b.bottom; const flip=below<240&&above>below; const MENU_MAX=520; const room=Math.min(MENU_MAX,Math.max(140,(flip?above:below)-14)); tkPanel.style.maxHeight=room+"px"; const h=Math.min(tkPanel.offsetHeight,room); const top=flip?b.top+scrollY-h-6:b.bottom+scrollY+6; tkPanel.style.left=left+"px"; tkPanel.style.top=Math.max(scrollY+8,Math.min(top,scrollY+innerHeight-h-8))+"px"; pickBtn(sel).setAttribute("aria-expanded","true"); tkFind.focus(); }; const tkClose=()=>{ if(!tkSel)return; pickBtn(tkSel)?.setAttribute("aria-expanded","false"); tkPanel.classList.add("hide");tkSel=null; }; const tkChoose=v=>{ const sel=tkSel;if(!sel)return; tkClose(); if(sel.value===v&&v!=="__custom")return; sel.value=v; sel.dispatchEvent(new Event("change",{bubbles:true})); }; for(const sel of [fromSel,toSel]){ const b=pickBtn(sel); if(b)b.addEventListener("click",e=>{e.stopPropagation();tkSel===sel?tkClose():tkOpen(sel)}); } tkList.addEventListener("click",e=>{ const r=e.target.closest(".tkr"); if(!r||r.getAttribute("aria-disabled")==="true")return; tkChoose(r.dataset.value); }); tkFind.addEventListener("input",tkRows); tkPanel.addEventListener("keydown",e=>{ const rows=[...tkList.querySelectorAll('.tkr:not([aria-disabled="true"])')]; if(e.key==="Escape"){e.preventDefault();const s=tkSel;tkClose();pickBtn(s)?.focus();return} if(e.key==="ArrowDown"||e.key==="ArrowUp"){ e.preventDefault(); if(!rows.length)return; tkCur=e.key==="ArrowDown"?(tkCur+1)%rows.length:(tkCur<=0?rows.length:tkCur)-1; rows.forEach((r,i)=>r.classList.toggle("cur",i===tkCur)); rows[tkCur].scrollIntoView({block:"nearest"}); return; } if(e.key==="Enter"){ const r=tkCur>=0?rows[tkCur]:rows.length===1?rows[0]:null; if(r){e.preventDefault();tkChoose(r.dataset.value)} } }); tkPanel.addEventListener("click",e=>e.stopPropagation()); document.addEventListener("click",tkClose); addEventListener("resize",()=>{if(!matchMedia("(pointer:coarse)").matches)tkClose()}); addEventListener("scroll",e=>{if(tkSel&&!tkPanel.contains(e.target))tkClose()},true); const render=()=>{ if(!account){swap.textContent="Connect Wallet";swap.disabled=false;return} if(tab==="book"){ rate.textContent=""; const f=TOKENS[fromSel.value],t=TOKENS[toSel.value]; if(!f||!t){swap.textContent="Place order";swap.disabled=true;return} if(f.std==="nft"&&t.std==="nft"){ swap.textContent="One side must be a token";swap.disabled=true;return} if(t.std==="nft"){ const oneId=nftId.value.trim(); if(oneId&&!/^\d+$/.test(oneId)){ swap.textContent="Token id must be a number";swap.disabled=true;return} const climbing=kind.value==="floor"; if(kind.value==="dutch"){ swap.textContent="A bid is fixed or climbing, not decaying";swap.disabled=true;return} if(oneId&&climbing){ swap.textContent="A climbing bid takes any id — clear the token id"; swap.disabled=true;return} if(!oneId){ const q=outAmt.value.trim(); if(q&&!/^\d+$/.test(q)){ swap.textContent="How many? a whole number";swap.disabled=true;return} if(q&&!BigInt(q)){swap.textContent="Bid for at least one";swap.disabled=true;return} if(q&&BigInt(q)>(1n<<128n)-1n){ swap.textContent="Too many to bid for at once";swap.disabled=true;return} } let bidAmt=0n; try{bidAmt=amt.value.trim()?parseUnits(amt.value.trim(),f.dec):0n}catch{} if(!bidAmt){ swap.textContent=climbing?"Set the most you will pay":"Set what you will pay"; swap.disabled=true;return} if(climbing){ let openAmt=0n; try{openAmt=floorAmt.value.trim()?parseUnits(floorAmt.value.trim(),f.dec):0n}catch{} if(!openAmt){swap.textContent="Set an opening bid";swap.disabled=true;return} if(openAmt>bidAmt){swap.textContent="Opening bid exceeds the maximum";swap.disabled=true;return} if(!+dly.value){swap.textContent="A climbing bid needs a window";swap.disabled=true;return} }else if(!oneId&&!+dly.value){ swap.textContent="A collection bid needs a window";swap.disabled=true;return} if(bidAmt>fromBalance){swap.textContent="Insufficient balance";swap.disabled=true;return} swap.textContent=oneId?`Bid for ${t.sym} #${oneId}` :climbing?`Climbing bid for any ${t.sym}`:`Bid for any ${t.sym}`; swap.disabled=false;return} if(f.std==="nft"){ if(kind.value!=="fixed"){ swap.textContent="An NFT sells at a fixed price";swap.disabled=true;return} if(!/^\d+$/.test(nftId.value.trim())){ swap.textContent="Name the token id to sell";swap.disabled=true;return} let ask=0n; try{ask=outAmt.value.trim()?parseUnits(outAmt.value.trim(),t.dec):0n}catch{} if(!ask){swap.textContent="Set a price";swap.disabled=true;return} swap.textContent=`List ${f.sym} #${nftId.value.trim()}`;swap.disabled=false;return} const dutch=kind.value==="dutch",bid=kind.value==="floor"; let sell=0n,want=0n,floor=0n,badOrderAmount=false; try{if(amt.value.trim())sell=parseUnits(amt.value.trim(),f.dec); if(outAmt.value.trim())want=parseUnits(outAmt.value.trim(),t.dec); if((dutch||bid)&&floorAmt.value.trim())floor=parseUnits(floorAmt.value.trim(),bid?f.dec:t.dec)} catch{badOrderAmount=true} if(badOrderAmount){swap.textContent="Invalid order amount";swap.disabled=true;return} if(!sell||!want){swap.textContent=bid?"Place bid":"Place order";swap.disabled=true;return} if(bid){ if(t.addr===ZERO){swap.textContent="Pick a token to bid for";swap.disabled=true;return} if((f.addr===ZERO?WETH:f.addr).toLowerCase()===t.addr.toLowerCase()){ swap.textContent="Pick different token";swap.disabled=true;return} if(!floor){swap.textContent="Set an opening bid";swap.disabled=true;return} if(floor>sell){swap.textContent="Opening exceeds maximum";swap.disabled=true;return} if(+dly.value===0){swap.textContent="Choose a bid window";swap.disabled=true;return} if(sell>fromBalance){swap.textContent="Insufficient balance";swap.disabled=true;return} swap.textContent=`Bid ${trimAmt(floor,f.dec)} → ${trimAmt(sell,f.dec)} ${f.sym} for ${trimAmt(want,t.dec)} ${t.sym}`; swap.disabled=false;return; } if(f.addr===ZERO&&t.addr===WETH){swap.textContent="Pick different token";swap.disabled=true;return} if(!dutch&&f.addr===WETH&&t.addr===ZERO){swap.textContent="Pick different token";swap.disabled=true;return} if(dutch&&floor>want){swap.textContent="Floor exceeds start";swap.disabled=true;return} if(dutch&&+dly.value===0){swap.textContent="Choose decay duration";swap.disabled=true;return} if(sell>fromBalance){swap.textContent="Insufficient balance";swap.disabled=true;return} swap.textContent=dutch ?`Dutch ${trimAmt(sell,f.dec)} ${f.sym} · ${trimAmt(want,t.dec)} → ${trimAmt(floor,t.dec)} ${t.sym}` :`Place ${fill.value==="1"?"":"all-or-nothing "}order \u2014 ${trimAmt(sell,f.dec)} ${f.sym} \u2192 ${trimAmt(want,t.dec)} ${t.addr===ZERO?"WETH":t.sym}`; { const qs=t.addr===ZERO?"ETH":t.sym; rate.textContent=dutch ?`Falls from ${trimAmt(want,t.dec)} to ${trimAmt(floor,t.dec)} ${qs} over ${rel(+dly.value)}, then rests at ${trimAmt(floor,t.dec)} ${qs} ` +(+dRest.value?`for ${rel(+dRest.value)} and returns to you`:`until you cancel`) :`${fill.value==="1"?"Fills in any amount":"Fills all at once"} at ${trimAmt(want,t.dec)} ${t.addr===ZERO?"WETH":t.sym} for ${trimAmt(sell,f.dec)} ${f.sym}` +(+dly.value?`, expiring in ${rel(+dly.value)}`:", and never expires"); } swap.disabled=false;return; } if(tab==="send"){ if(!sendReady){ let n=0n;try{n=parseUnits(amt.value.trim(),TOKENS[fromSel.value].dec)}catch{} swap.textContent=n>0n?"Name a recipient":"Enter an amount"; swap.disabled=true;return} if(sendReady.amount>fromBalance){swap.textContent="Insufficient balance";swap.disabled=true;return} const a=`${trimAmt(sendReady.amount,sendReady.token.dec)} ${sendReady.token.sym}`,dv=+dly.value; if(dv&&sendTipWei>0n&&sendReady.token.addr===ZERO &&sendReady.amount+sendTipWei>fromBalance){ swap.textContent="Insufficient ETH for amount + keeper tip";swap.disabled=true;return} swap.textContent=(dv?`Lock ${a} for ${rel(dv)}`:`Send ${a}`)+` \u2192 ${sendReady.label}`; swap.disabled=false;return; } if(quoting){swap.textContent="Quoting…";swap.disabled=true;return} if(!last){swap.textContent="Swap";swap.disabled=true;return} if(last.amountIn>fromBalance){swap.textContent="Insufficient balance";swap.disabled=true;return} swap.textContent="Swap";swap.disabled=false; }; syncIcons(); render(); const isRejection=e=>e?.code===4001||/user\s+reject|user\s+denied/i.test(e?.message||""); async function connect(){ if(!window.ethereum){stat.textContent=NO_WALLET;return} if(connecting)return; connecting=true; swap.textContent="Connecting…";swap.disabled=true; lnGo.textContent="Connecting…";lnGo.disabled=true; try{ let accs; try{accs=await rpc("eth_requestAccounts",[])} catch(e){err(e);return} if(!accs[0])return; let chainId=await rpc(I,[]); if(+chainId!==1){ try{await rpc("wallet_switchEthereumChain",[{chainId:"0x1"}])} catch(e){stat.textContent=isRejection(e)?"":"Switch to Ethereum mainnet.";return} chainId=await rpc(I,[]); if(+chainId!==1){stat.textContent="Switch to Ethereum mainnet.";return} } sessionStorage.removeItem("dc"); account=accs[0]; const keepPair=pairAddrs(); await loadTokenList(); adoptList(keepPair); showAddr(); refreshBalance(); update(); loadPos(); syncChart(); if(lnMode)lnQuote(); }finally{connecting=false;swap.disabled=false; lnGo.disabled=false;lnGo.textContent=account?"Launch":"Connect Wallet";render()} } const lqReserveGas=()=>lqList.querySelector(".lqnew")?LQ_CREATE_GAS+300000n:400000n; const lqFillMax=(tok,max)=>{ const box=lqList.querySelector(".lqadd:not(.hide)"); const pair=chPair(); if(!box||!pair)return false; const side=pair[0].addr.toLowerCase()===tok.addr.toLowerCase()?"0":"1"; const el=box.querySelector(`.lqin[data-side="${side}"]`); if(!el)return false; el.value=formatUnits(max,tok.dec); el.dispatchEvent(new Event("input",{bubbles:true})); return true; }; bal1.addEventListener("click",async e=>{ if(e.target.tagName!=="A")return; e.preventDefault(); const t=TOKENS[toSel.value]; if(!t)return; let reserve=0n; if(t.addr===ZERO){ try{reserve=BigInt(await rpc("eth_gasPrice",[]))*lqReserveGas()}catch{} } const max=toBalance>reserve?toBalance-reserve:0n; if(lqFillMax(t,max))return; outAmt.value=formatUnits(max,t.dec); fitFont(outAmt); lqPreviewSoon(); }); bal.addEventListener("click",async e=>{ if(e.target.tagName!=="A")return; e.preventDefault(); const f=TOKENS[fromSel.value]; if(!f)return; let reserve=0n; if(f.addr===ZERO){ try{reserve=BigInt(await rpc("eth_gasPrice",[])) *(lqMode?lqReserveGas():tab==="swap"?900000n:tab==="book"?350000n :+dly.value?(tipCk.checked?200000n+TIP_GAS:200000n):30000n)}catch{} } const max=fromBalance>reserve?fromBalance-reserve:0n; if(lqMode&&lqFillMax(f,max))return; amt.value=formatUnits(max,f.dec); fitFont(amt); if(lqMode)return; setMode("in"); update(); }); let seq=0; const REVERTS={ "1ab7da6b":"That took too long and the deadline passed, so nothing was placed. Try again — you were not charged for an order.", "98c2c368":"The order was refused as malformed. Check the amounts and the expiry.", "7939f424":"The token transfer was refused — usually a missing or spent approval. Try again and approve first.", "90b8ec18":"The token transfer was refused by the token itself.", "3e3f8f73":"The approval was refused by the token.", "b12d13eb":"Ether could not be sent to the recipient — a contract there may not accept it.", "ab143c06":"That call re-entered and was stopped.", }; const explain=e=>{ if(e?.noWallet)return NO_WALLET; const s=String(e?.data?.data||e?.data||e?.message||e||""); const m=/0x([0-9a-fA-F]{8})\b/.exec(s); const hit=m&&REVERTS[m[1].toLowerCase()]; return hit||("Error: "+s.slice(0,110)); }; const err=e=>stat.textContent=isRejection(e)?"":explain(e); const settle=async tx=>{ if(!tx){stat.textContent="Done";return} if(!/^0x[0-9a-f]{64}$/i.test(tx))throw Error("bad tx"); stat.innerHTML=txLink(tx,"Sent");await waitTx(tx);stat.innerHTML=txLink(tx,"Done")}; const txLink=(h,label)=>`${label} <a href="https://etherscan.io/tx/${h}" target="_blank" rel="noreferrer">${h.slice(0,10)}…${h.slice(-6)}</a>`; let autoQ=0; async function update(auto){ if(!auto)autoQ=0; syncIcons(); if(lqMode)return loadLq(); if(tab==="book")return render(); if(tab==="send")return updateSend(); const my=++seq; quoting=false; last=null; rate.textContent=""; if(!lqMode&&!lnMode)rcvHdr.textContent="You receive"; render(); const f=TOKENS[fromSel.value], t=TOKENS[toSel.value]; if(!f||!t)return; if(f.addr===t.addr){stat.textContent="Pick different tokens.";return} stat.textContent=""; const isIn=mode==="in"; const inEl=isIn?amt:outAmt, outEl=isIn?outAmt:amt, inTok=isIn?f:t; outEl.value=""; fitFont(outEl); if(!inEl.value.trim())return; let swapAmt; try{swapAmt=parseUnits(inEl.value.trim(),inTok.dec)} catch(e){const q=inEl.value.trim(); if(q&&!/\.$/.test(q))stat.textContent=/decimals/.test(e.message)?`${inTok.sym} has ${inTok.dec} decimals`:"Invalid amount"; return} if(swapAmt<=0n)return; const rv=rc.value.trim(); let rcv=""; if(rv){ const fail=m=>{rc.classList.add("bad");rcvEl.textContent=""; outEl.value="";fitFont(outEl);stat.textContent=m}; const bad=rcErr(rv); if(bad){fail(bad);return} if(isAddr(rv))rcv=rv; else{ rcvEl.textContent="resolving..."; try{rcv=await rcvOf(rv)} catch(e){if(my!==seq)return;fail(e&&e.offchain?e.message:"Name not registered");return} if(my!==seq)return; if(!rcv){fail("Name not registered");return} } rcvEl.textContent=rcv; }else rcvEl.textContent=""; rc.classList.remove("bad"); if(!rv&&f.addr===WETH&&t.addr===ZERO){ outEl.value=inEl.value;fitFont(outEl); rate.textContent=`1 ${f.sym} = 1 ${t.sym}`; last={callData:"0x2e1a7d4d"+encUint(swapAmt),msgValue:0n,amountIn:swapAmt,from:f,to:WETH,recipient:"",exp:Date.now()+QUOTE_TTL}; render();return; } if(!rv&&f.addr===ZERO&&t.addr===WETH){ outEl.value=inEl.value;fitFont(outEl); rate.textContent=`1 ${f.sym} = 1 ${t.sym}`; last={callData:"0xd0e30db0",msgValue:swapAmt,amountIn:swapAmt,from:f,to:WETH,recipient:"",exp:Date.now()+QUOTE_TTL}; render();return; } const pct=Math.min(10,Math.max(.01,+slip.value||.5)); const slipBps=BigInt(Math.round(pct*100)); const deadline=BigInt(Math.floor(Date.now()/1e3)+1800); outEl.value="...";fitFont(outEl);quoting=true;render(); const acct=account; const gaveUp0=mcGaveUp,ok0=mcOk,failed0=mcFailed; try{ const a=encAddr(rcv||acct||ZERO),rf=encAddr(acct||ZERO),tl=encBool(!isIn)+encAddr(f.addr)+encAddr(t.addr)+encUint(swapAmt)+encUint(slipBps)+encUint(deadline); const _rq=[]; const Q=(x,d,u,v,S,sb,mv)=>{_rq.push({to:ZQUOTER,data:"0x"+x+d,u,v,S,sb,mv});return _rq.length-1}; let r=null; const candKey=f.addr.toLowerCase()+":"+t.addr.toLowerCase(); const cachedCandidates=candCache[candKey]; const quoteBlock=cachedCandidates&&Date.now()-cachedCandidates.at<15000 ?cachedCandidates.block:await rpc("eth_blockNumber",[]); const candJob=acct?swapCandidates(f.addr,t.addr,quoteBlock).catch(()=>{ const x=[];x.unavailable=true;return x }):Promise.resolve([]); const gasPriceJob=acct?rpc("eth_gasPrice",[]).then(BigInt).catch(()=>0n):Promise.resolve(0n); const v4Job=isIn?quoteV4Pools(f,t,swapAmt,quoteBlock).catch(()=>null):Promise.resolve(null); const preJob=isIn?quotePrecision(f,t,swapAmt,PROUTE,quoteBlock).catch(()=>null):Promise.resolve(null); const SRC_CURVE=5; let curveOnlyOut=false; const exactOutSafe=y=>{if(isIn||!y.sources||!y.sources.includes(SRC_CURVE))return true;curveOnlyOut=true;return false}; const pick=y=>{if(!y)return;if(!exactOutSafe(y))return;const v=isIn?y.best.amountOut:y.best.amountIn;if(!v)return; if(!r||(isIn?v>r.best.amountOut:v<r.best.amountIn))r=y}; const tl0=encBool(!isIn)+encAddr(f.addr)+encAddr(t.addr)+encUint(swapAmt)+encUint(0n)+encUint(deadline); const jobs=[ [Q("e7798987",a+tl,0,4,0,0,6)], [Q("e453166e",a+rf+tl0,4,9),Q("e453166e",a+rf+tl,4,9)], [Q("4c464f59",a+tl0,8,13),Q("4c464f59",a+tl,8,13)]]; let splitSlip=0n; if(isIn){ const w=slipBps*3n,SS=w<150n?150n:w>500n?500n:w; splitSlip=SS; const ps=encAddr(f.addr)+encAddr(t.addr)+encUint(swapAmt)+encUint(SS)+encUint(deadline); for(const x of["892af013","85f86a90"])jobs.push([Q(x,a