memoscan
← all memos

Memo 0xb6f4ad5f…183b4c on Ethereum

0x68575b07…67c7·#25,913,246·view on Etherscan
>=mc3Cap&&mc3Cap<MC3_MAX&&r.every(x=>x!=null)&&++mc3Won>=2){mc3Cap++;mc3Won=0;mc3Save()} return r; } catch(e){ mc3Won=0; if(cs.length<2||depth>=8){mcGaveUp+=cs.length;return cs.map(()=>null)} const h=cs.length>>1; if(h<mc3Cap){mc3Cap=h;mc3Save()} await new Promise(r=>setTimeout(r,150*(depth+1))); return fan(h); } }; let bnVal="",bnAt=0,bnJob=null; const BN_TTL=12000; const bnFetch=()=>bnJob||(bnJob=rpc("eth_blockNumber",[]) .then(n=>{bnVal=n;bnAt=Date.now();return n}) .finally(()=>{bnJob=null})); const blockNow=()=>{ const age=Date.now()-bnAt; if(!bnVal||age>=BN_TTL)return bnFetch(); if(age>BN_TTL/2)bnFetch().catch(()=>{}); return Promise.resolve(bnVal); }; const codeSeen={}; const CODE_MISS_TTL=60000; const hasCode=async a=>{ if(codeSeen[a]===true)return true; const miss=codeSeen[a]; if(miss&&Date.now()-miss<CODE_MISS_TTL)return false; const h=await rpc("eth_getCode",[a,L]); const ok=(h||"").length>4; codeSeen[a]=ok||Date.now(); return ok; }; const REF_N=100n; const CH_WICK_CAP=3; const IMPACT_HIDE=50n, IMPACT_WARN=500n, IMPACT_CONFIRM=1500n, IMPACT_TYPED=3000n; const impactBps=(v,ref,eo)=>{if(!v||!ref)return null;const lin=ref*REF_N; if(lin===0n)return 0n; return eo?(v<=lin?0n:(v-lin)*10000n/lin):(v>=lin?0n:(lin-v)*10000n/lin)}; const safeSym=s=>String(s??"").replace(/[<>&"'`]/g,"") .replace(/[\u0000-\u001f\u007f]/g,"").trim().slice(0,16)||"?"; const safeUrl=u=>{u=String(u??"").trim(); return u.length<=32768&&/^(?:https:\/\/|data:image\/[a-z.+-]+;base64,)[^\s<>"'`\\]+$/i.test(u)?u:""}; const safeDataUrl=u=>{u=String(u??"").trim(); return u.length<=32768&&/^data:image\/[a-z.+-]+;base64,[A-Za-z0-9+/=]+$/i.test(u)?u:""}; const genIcon=sym=>`<svg width="20" height="20" viewBox="0 0 32 32"><circle cx="16" cy="16" r="16" fill="#999"/><text x="16" y="21" text-anchor="middle" fill="#fff" font-size="13" font-weight="600" font-family="system-ui">${(safeSym(sym)[0]||"?").toUpperCase()}</text></svg>`; const STORE=()=>CHAIN_ID===1?"zswap:custom":"zswap:custom:"+CHAIN_ID; function keepToken(t){ if(!t||!t.addr)return; const a=t.addr.toLowerCase(); try{const arr=JSON.parse(localStorage.getItem(STORE())||"[]") .filter(x=>String(x?.addr||"").toLowerCase()!==a); arr.push({sym:t.sym,addr:a,dec:t.dec,std:t.std,cause:t.cause?1:0}); localStorage.setItem(STORE(),JSON.stringify(arr))}catch{} } const SEL_SUPPORTS="01ffc9a7",IFACE_721="80ac58cd",IFACE_1155="d9b67a26"; const supports=id=>"0x"+SEL_SUPPORTS+id.padEnd(64,"0"); async function addCustomToken(a,keep=1){ a=a.toLowerCase(); if(!/^0x[0-9a-f]{40}$/.test(a))throw Error("invalid address"); const i=TOKENS.findIndex(t=>t.addr.toLowerCase()===a); if(i>=0)return i; if((await rpcRead("eth_getCode",[a,L],2)).length<5)throw Error("no contract at that address"); const[symRet,decRet,is721,is1155]=await mc3Deep([ {to:a,data:"0x95d89b41"},{to:a,data:"0x313ce567"}, {to:a,data:supports(IFACE_721)},{to:a,data:supports(IFACE_1155)}]); let uriRet=null; try{uriRet=await rpc(C,[{to:a,data:"0x"+SEL_CONTRACTURI},L])}catch{} const yes=h=>{try{return !!h&&BigInt(h)===1n}catch{return false}}; const dup=TOKENS.findIndex(t=>t.addr.toLowerCase()===a); if(dup>=0)return dup; let sym="?"; try{sym=decodeString(symRet||"0x").trim().replace(/[<>&"'`]/g,"").replace(/[\u0000-\u001f\u007f]/g,"").slice(0,16)||"?"}catch{} if(TOKENS.some(t=>t.sym.toLowerCase()===sym.toLowerCase()))sym+=" "+a.slice(0,6)+"\u2026"; if(yes(is1155)&&!yes(is721))throw Error("ERC-1155 is not supported"); const std=yes(is721)?"nft":"ft"; let dec=0; if(std==="ft"){ dec=Number(BigInt(decRet&&decRet!=="0x"?decRet:"0x0")); if(!decRet||decRet==="0x"||!Number.isInteger(dec)||dec<0||dec>36)throw Error("not an ERC-20 or ERC-721"); } let selfArt="";try{selfArt=imgFromContractURI(uriRet?decodeString(uriRet):"")}catch{} if(selfArt)logoCache[a]=selfArt; TOKENS.push({sym,addr:a,dec,std,cust:1, icon:selfArt?`<img width="20" height="20" style="border-radius:50%;object-fit:cover" src="${selfArt}" alt="">`:genIcon(sym)}); if(keep)keepToken(TOKENS[TOKENS.length-1]); return TOKENS.length-1; } function restoreCustom(){try{for(const t of JSON.parse(localStorage.getItem(STORE())||"[]")){ const addr=(t?.addr||"").toLowerCase(); const dec=+t?.dec; if(/^0x[0-9a-f]{40}$/.test(addr)&&Number.isInteger(dec)&&dec>=0&&dec<=36&&!TOKENS.some(x=>x.addr.toLowerCase()===addr)){ const sym=String(t.sym||"?").replace(/[<>&"'`]/g,"").replace(/[\u0000-\u001f\u007f]/g,"").slice(0,16)||"?"; TOKENS.push({sym,addr,dec,std:t.std==="nft"?"nft":"ft",cust:1,icon:genIcon(sym), ...(t.cause?{cause:1}:{})}); } }}catch{}} restoreCustom(); const QUOTE_TTL=45000; let account=null,connecting=false,last=null,fromBalance=0n,mode="in",bSeq=0,tab="swap",sendReady=null,sSeq=0,sendD="0",bookD="86400"; let quoting=false; let lqMode=false; const readBal=async t=>BigInt(t.addr===ZERO ?await rpc("eth_getBalance",[account,L]) :await rpc(C,[{to:t.addr,data:"0x"+SEL_BALANCEOF+encAddr(account)},L])); const showBal=(el,v,dec)=>{const n=+formatUnits(v,dec); const pretty=n>=1?n.toLocaleString("en-US",{maximumFractionDigits:4}):sigAmt(v,dec,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=""; let born=""; let cau=""; TOKENS.forEach((t,i)=>{const o=`<option value="${i}">${t.sym}</option>`; if(t.std==="nft")nft+=o;else if(t.cause)cau+=o;else if(t.launched)born+=o;else ft+=o}); return ft +(cau?`<optgroup label="Causes — backed and burned, never traded">${cau}</optgroup>`:"") +(born?`<optgroup label="Launched on zSwap — not curated">${born}</optgroup>`:"") +(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 me=()=>(account||"").toLowerCase(); 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()}; let listFresh=false; const adoptList=keep=>{ cbDisarm(); listFresh=true; 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 tkAct=id=>{if(id)tkFind.setAttribute("aria-activedescendant",id); else tkFind.removeAttribute("aria-activedescendant")}; const tkRows=()=>{ const q=tkFind.value.trim().toLowerCase(); tkList.textContent=""; tkCur=-1;tkAct(""); 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||(opt.value==="__custom"?"": (listLive?(rankFellBack?"zList — listing order":"zList — ranked by conviction"):"Built-in token list")); 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.id="tkr"+n; 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 a=/^0x[0-9a-f]{40}$/.test(q)?q:""; if(a){ const r=document.createElement("button"); r.type="button";r.className="tkr"; const tx=document.createElement("span");tx.className="tkt"; const top=document.createElement("span");top.className="tks"; const b=document.createElement("b");b.textContent="Use "+short(a);top.appendChild(b); tx.appendChild(top); const d=document.createElement("span");d.className="tkd"; d.textContent="Not listed \u2014 read it from chain"; tx.appendChild(d);r.appendChild(tx); r.onclick=async e=>{ e.stopPropagation(); if(r.dataset.busy)return; r.dataset.busy="1";b.textContent="Reading\u2026"; try{const i=await addCustomToken(a);rebuild();tkChoose(String(i))} catch(e){delete r.dataset.busy;b.textContent="Use "+short(a); d.textContent=(e&&e.message)||"could not read that address"}}; frag.appendChild(r); }else{const e=document.createElement("div");e.className="tkempty";e.textContent="No token matches that.";frag.appendChild(e)} } tkList.classList.toggle("fresh",listFresh); listFresh=false; 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({preventScroll:true}); 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,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-h-6:b.bottom+6; tkPanel.style.left=left+"px"; tkPanel.style.top=Math.max(8,Math.min(top,innerHeight-h-8))+"px"; pickBtn(sel).setAttribute("aria-expanded","true"); tkFind.focus({preventScroll:true}); }; const tkClose=()=>{ if(!tkSel)return; pickBtn(tkSel)?.setAttribute("aria-expanded","false"); tkPanel.classList.add("hide");tkSel=null;tkCur=-1;tkAct(""); }; 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"}); tkAct(rows[tkCur].id); return; } if(e.key==="Enter"){ const r=tkCur>=0?rows[tkCur]:rows.length===1?rows[0]:null; if(r){e.preventDefault();r.dataset.value?tkChoose(r.dataset.value):r.click()} } }); 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=nftIdIn(t.addr,nftId.value); if(oneId&&!/^\d+$/.test(oneId)){ swap.textContent=isWns(t.addr)?"Token id must be a number, or a .wei name":"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 ${nftLabel(t.sym,t.addr,nftId.value)}` :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(nftIdIn(f.addr,nftId.value))){ swap.textContent=isWns(f.addr)?"Name the .wei name, or the token id, to sell":"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 ${nftLabel(f.sym,f.addr,nftId.value)}`;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||""); const W6963=[]; addEventListener("eip6963:announceProvider",e=>{ const d=e.detail; if(!d||!d.provider||!d.info||W6963.some(x=>x.info.uuid===d.info.uuid))return; W6963.push(d)}); const wkScan=()=>{try{dispatchEvent(new Event("eip6963:requestProvider"))}catch{}}; wkScan(); const WC_PID="1e8390ef1c1d8a185e035912a1409749"; const WC_ICON='<svg viewBox="0 0 400 400" fill="none" aria-hidden="true"><circle cx="200" cy="200" r="200" fill="#3396ff"/><path fill="#fff" d="m122.519 148.965c42.791-41.729 112.171-41.729 154.962 0l5.15 5.022c2.14 2.086 2.14 5.469 0 7.555l-17.617 17.18c-1.07 1.043-2.804 1.043-3.874 0l-7.087-6.911