0x68575b07…67c7·#25,914,174·view on Etherscan
ta","eth_signTypedData_v3","eth_signTypedData_v4"];
const wcToWallet=m=>m.indexOf("wallet_")===0||WC_SIGN.indexOf(m)>=0;
async function wcRpc(method,params){
try{return await nodeRead(method,params)}
catch(e){if(e&&e.code!=null)throw e;
throw Error("Could not reach "+wcHost()+" for reads. Pick another node from the WalletConnect panel.")}}
const wcRelay=WCCLI(WCU,u=>new WebSocket(u));
const qrSvg=m=>{let d="";
for(let r=0;r<m.size;r++)for(let c=0;c<m.size;c++)if(m.modules[r][c])d+="M"+c+" "+r+"h1v1h-1z";
return '<svg viewBox="-4 -4 '+(m.size+8)+" "+(m.size+8)+'" role="img" aria-label="WalletConnect pairing code" style="width:100%;height:auto;background:#fff;border-radius:.3em"><path fill="#000" d="'+d+'"/></svg>'};
const wcShow=uri=>{
wkList.textContent="";
const box=document.createElement("div");
box.className="wcq";
box.innerHTML=qrSvg(QR8.build(uri));
const cp=document.createElement("button");
cp.type="button";cp.className="fclink";cp.textContent="copy link";
cp.onclick=()=>{navigator.clipboard?navigator.clipboard.writeText(uri).then(()=>{cp.textContent="copied"}).catch(()=>{cp.textContent="copy blocked"}):cp.textContent="copy blocked"};
const note=document.createElement("div");
note.className="wcn";
note.textContent="Scan with a mobile wallet, or ";
note.appendChild(cp);
const nd=document.createElement("div");
nd.className="wcn wcnode";
nd.appendChild(document.createTextNode("Reads via "+wcHost()+" "));
const ch=document.createElement("button");
ch.type="button";ch.className="fclink";ch.textContent="change";
ch.onclick=()=>{
const v=prompt("HTTPS Ethereum RPC used for reads — it is pinned to the front of the read pool (the DAO-curated list, then the page's seeds)."
+" Signing always goes to your wallet. Leave blank for the default.",wcNode());
if(v===null)return;
const t=v.trim();
try{if(!t)localStorage.removeItem(RPC_STORE);
else if(/^https:\/\/\S+$/i.test(t))localStorage.setItem(RPC_STORE,t);
else return}catch{}
nd.firstChild.nodeValue="Reads via "+wcHost()+" "};
nd.appendChild(ch);
wkList.appendChild(box);wkList.appendChild(note);wkList.appendChild(nd);
wkHdr.textContent="WalletConnect";
wkWrap.classList.remove("hide");
const back=document.activeElement;
cp.focus({preventScroll:true});
return new Promise((res,rej)=>{
const esc=e=>{if(e.key==="Escape")stop()};
const off=()=>{removeEventListener("keydown",esc);removeEventListener("keydown",wkTrap,true);
wkWrap.onclick=null;if(back&&back.focus)try{back.focus()}catch{}};
const stop=()=>{off();rej(Object.assign(Error(""),{code:4001}))};
wkWrap.onclick=e=>{if(e.target===wkWrap)stop()};
addEventListener("keydown",esc);
addEventListener("keydown",wkTrap,true);
wcShow.settle=()=>{off();res()}})};
async function wcConnect(){
const meta={name:"zSwap",description:"zSwap",url:location.origin,icons:[]};
const{uri,done}=await wcRelay.pair(WC_PID,meta);
const bail=wcShow(uri);
stat.textContent="Scan the code with your wallet.";
let sess;
try{sess=await Promise.race([done,bail])}
catch(e){wcRelay.close();throw e}
finally{if(wcShow.settle)wcShow.settle();
wkHdr.textContent="Choose a wallet";
wkWrap.classList.add("hide")}
const accts=sess.accounts.filter(a=>a.slice(0,9)==="eip155:1:").map(a=>a.split(":").pop());
if(!accts.length){wcRelay.close();throw Error("That wallet settled no Ethereum mainnet account — switch it to Ethereum and reconnect.")}
wcRead=sess.methods.indexOf("eth_call")>=0;
const read=async(method,params)=>{
try{return await wcRpc(method,params)}
catch(e){
if(e&&e.code!==undefined||!wcRead)throw e;
return wcRelay.request(sess,method,params||[])}};
const evs=[];
wcRelay.on(ev=>{if(ev&&ev.t==="closed")location.reload();
if(!ev||ev.t!=="session")return;
const s=ev.m;
if(!s)return;
if(s.method==="wc_sessionUpdate")return evs.forEach(f=>f("reload",null));
if(s.method!=="wc_sessionEvent")return;
const e=s.params&&s.params.event||{};let d=e.data;
if(e.name==="chainChanged"&&typeof d==="string"&&d.includes(":"))d=d.split(":").pop();
if(e.name==="accountsChanged"&&Array.isArray(d))d=d.map(a=>typeof a==="string"&&a.includes(":")?a.split(":").pop():a);
if(e.name==="chainChanged"||e.name==="accountsChanged")evs.forEach(f=>f(e.name,d))});
return{request:({method,params})=>
method==="eth_requestAccounts"||method==="eth_accounts"?Promise.resolve(accts):
method==="eth_chainId"?Promise.resolve("0x1"):
wcToWallet(method)?wcRelay.request(sess,method,params||[]):
read(method,params),
on:(t,f)=>{if(t==="chainChanged"||t==="accountsChanged")evs.push((n,d)=>{if(n==="reload"||n===t)try{f(d)}catch{}})}}}
let wcRead=true;
const wkWrap=document.getElementById("wkWrap"),wkList=document.getElementById("wkList");
const wkChoices=()=>W6963.map(d=>({name:d.info.name,icon:d.info.icon,rdns:d.info.rdns,get:()=>d.provider}))
.concat([{name:"WalletConnect",svg:WC_ICON,rdns:"wc",get:wcConnect}]);
const WK="zswap:wk";
const wkRestore=async()=>{
const id=LS[WK];
if(PROV||!id||id==="wc")return;
wkScan();
for(let i=0;i<8;i++){
const m=W6963.filter(x=>x.info.rdns===id),d=m.length===1?m[0]:null;
if(d){
try{const a=await Promise.race([d.provider.request({method:"eth_accounts"}),
new Promise(r=>setTimeout(()=>r(null),1500))]);
if(a&&a[0])PROV=d.provider}catch{}
return}
await new Promise(r=>setTimeout(r,50));
}};
const wkTrap=e=>{
if(e.key!=="Tab")return;
const f=[...wkPanel.querySelectorAll('button,[href],input,select,textarea,[tabindex]:not([tabindex="-1"])')]
.filter(x=>!x.disabled&&x.offsetParent!==null);
if(!f.length)return;
const a=f[0],z=f[f.length-1],cur=document.activeElement;
if(e.shiftKey?cur===a||!wkPanel.contains(cur):cur===z){e.preventDefault();(e.shiftKey?z:a).focus()}
};
const wkPick=cs=>new Promise(res=>{
wkList.textContent="";
let done=false;
const back=document.activeElement;
const end=v=>{if(done)return;done=true;
wkWrap.classList.add("hide");removeEventListener("keydown",esc);
removeEventListener("keydown",wkTrap,true);
if(back&&back.focus)try{back.focus()}catch{}
res(v)};
const esc=e=>{if(e.key==="Escape")end(null)};
cs.forEach(c=>{
const b=document.createElement("button");
b.type="button";b.className="tkr";
if(c.icon){const im=document.createElement("img");im.src=c.icon;im.alt="";b.appendChild(im)}
else if(c.svg){const sp=document.createElement("span");sp.className="wki";sp.innerHTML=c.svg;b.appendChild(sp)}
b.appendChild(document.createTextNode(c.name));
b.onclick=()=>end(c);
wkList.appendChild(b)});
wkWrap.onclick=e=>{if(e.target===wkWrap)end(null)};
addEventListener("keydown",esc);
addEventListener("keydown",wkTrap,true);
wkWrap.classList.remove("hide");
wkList.firstChild?.focus()});
async function wkResolve(){
if(PROV)return true;
wkScan();
const inj=window.ethereum;
if(W6963.length<2&&inj)return true;
const cs=wkChoices();
const c=await wkPick(cs);
if(!c)return false;
stat.textContent="Connecting…";
try{PROV=await c.get()}
catch(e){if(!isRejection(e))err(e);return false}
try{if(c.rdns)LS[WK]=c.rdns}catch{}
wkBind(PROV);
return true}
async function connect(){
if(connecting)return;
connecting=true;
try{
if(!await wkResolve())return;
if(!prov()){stat.textContent=NO_WALLET;return}
swap.textContent="Connecting…";swap.disabled=true;
lnGo.textContent="Connecting…";lnGo.disabled=true;
wnGo.textContent="Connecting…";wnGo.disabled=true;
let accs;
try{accs=await rpc("eth_requestAccounts",[])}
catch(e){err(e);return}
if(!accs[0])return;
let chainId=await rpc(I,[]);
if(!CHAINS[+chainId]){
try{await rpc("wallet_switchEthereumChain",[{chainId:"0x1"}])}
catch(e){stat.textContent=isRejection(e)?"":"Switch to a supported network.";return}
chainId=await rpc(I,[]);
if(!CHAINS[+chainId]){stat.textContent="Switch to a supported network.";return}
}
setChain(+chainId);showNet();
sessionStorage.removeItem("dc");
account=accs[0];sOpen();
const keepPair=pairAddrs();
showAddr();
if(!listLive){
swap.textContent="Loading tokens\u2026";
await loadTokenList();
}
adoptList(keepPair);
refreshBalance();
update();
fcMine();
loadPos();
syncChart();
if(lnMode)lnKindQuote();
}finally{connecting=false;swap.disabled=false;
lnGo.disabled=false;lnGo.textContent=account?"Launch":"Connect Wallet";
wnGo.disabled=false;
if(wnMode){wnPaint();wnQuote();wnRoll()}else wnGo.textContent="Register";
if(pvMode)pvWake();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){
const g=lqReserveGas();
try{reserve=BigInt(await rpc("eth_gasPrice",[]))*g}catch{}
if(reserve<=0n)reserve=GAS_FLOOR*g;
}
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){
const g=lqMode?lqReserveGas():tab==="swap"?900000n:tab==="book"?350000n
:+dly.value?(tipCk.checked?200000n+TIP_GAS:200000n):30000n;
try{reserve=BigInt(await rpc("eth_gasPrice",[]))*g}catch{}
if(reserve<=0n)reserve=GAS_FLOOR*g;
}
const max=fromBalance>reserve?fromBalance-reserve:0n;
if(lqMode&&lqFillMax(f,max))return;
amt.value=formatUnits(max,f.dec);
fitFont(amt);
if(lqMode){lqPreviewSoon();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.",
"6fc70753":"That score name is not a valid label.",
"9c9cef39":"That score is too long to record.",
"7b2002ce":"Somebody already claimed that name — play again for a new one.",
"845eadf1":"The score minter is not holding arcade.wei.",
"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 str=v=>typeof v==="string"?v
:v&&typeof v.data==="string"?v.data
:v&&typeof v.message==="string"?v.message:"";
const s=str(e?.data)||str(e)||str(e?.error)||"";
const m=/0x([0-9a-fA-F]{8})\b/.exec(s);
const hit=m&&REVERTS[m[1].toLowerCase()];
if(hit)return hit;
if(!s)return "The wallet returned an error with no message"+(e&&e.code!==undefined?" (code "+e.code+")":"")+".";
return "Error: "+s.slice(0,110);
};
const err=e=>stat.textContent=isRejection(e)?"":explain(e);
const settle=async(tx,quiet)=>{
if(!tx){stat.textContent="Done";return}
if(!/^0x[0-9a-f]{64}$/i.test(tx))throw Error("bad tx");
stat.innerHTML=txLink(tx,"Sent");
try{await waitTx(tx)}catch(e){sFail();throw e}
stat.innerHTML=txLink(tx,"Done");if(!quiet)sGot()};
const txLink=(h,label)=>`${label} <a href="${chainCfg().explorer}/tx/${h}" target="_blank" rel="noreferrer">${h.slice(0,10)}…${h.slice(-6)}</a>`;
let autoQ=0,rankOpen=false;
async function update(auto){
if(!auto)autoQ=0;
syncIcons();
fcSync();
cbSync();
const my=++seq;
quoting=false;
if(wnMode||lnMode||pvMode)return;
if(lqMode)return loadLq();
if(tab==="book")return render();
if(tab==="send")return updateSend();
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=/^unclear comma/.test(e.message)?e.message:/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);rankBox.textContent="";rankBox.classList.add("hide");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,isIn:true,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,isIn:true,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 blockNow();
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);
let venueLost=false;
const v4Job=isIn?quoteV4Pools(f,t,swapAmt,quoteBlock).catch(()=>{venueLost=true;return null}):Promise.resolve(null);
const preJob=isIn?quotePrecision(f,t,swapAmt,PROUTE,quoteBlock).catch(()=>{venueLost=true;return null}):Promise.resolve(null);
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+ps,4,8,1,SS)]);
}
const tailStep=swapAmt/100n||1n,tailAmt=swapAmt>tailStep?swapAmt-tailStep:0n;
const tailJobs=[];
if(tailAmt){
const z=encBool(!isIn)+encAddr(f.addr)+encAddr(t.addr)+encUint(tailAmt)+encUint(0n)+encUint(deadline);
tailJobs.push(Q("e453166e",a+rf+z,4,9),Q("4c464f59",a+z,8,13));
if(isIn)for(const x of["892af013","85f86a90"]){
const ps=encAddr(f.addr)+encAddr(t.addr)+encUint(tailAmt)+encUint(splitSlip)+encUint(deadline);
tailJobs.push(Q(x,a+ps,4,8,1,splitSlip));
}
}
const refAmt=swapAmt/REF_N;
const iRef=refAmt>0n
?Q("e453166e",a+rf+encBool(!isIn)+encAddr(f.addr)+encAddr(t.addr)+encUint(refAmt)+encUint(0n)+encUint(deadline),4,9)
:-1;
const mcRaw=(await Promise.all(mc3Split(_rq,QPAIR)
.map(g=>mc3Deep(g.map(q=>({to:q.to,data:q.data})),quoteBlock)))).flat();
if(my!==seq)return;
const dec=_rq.map((q,i)=>{try{return mcRaw[i]?decQ(mcRaw[i],q.sb||slipBps,!isIn,q.u,q.v,q.S,q.mv):null}catch{return null}});
for(const g of jobs)pick(g.length>1?merge(dec[g[0]],dec[g[1]]):dec[g[0]]);
const zr=r;
if(isIn&&!(dec[jobs[1][0]]||dec[jobs[1][1]]||dec[jobs[2][0]]||dec[jobs[2][1]])){
const hq=await hubRoute(f,t,swapAmt,slipBps,deadline,rcv||acct||ZERO,acct||ZERO,quoteBlock).catch(()=>null);
if(my!==seq)return;
if(hq)pick(hq);
}
let tail=null;
for(const i of tailJobs){const y=dec[i];if(!y)continue;
const v=isIn?y.best.amountOut:y.best.amountIn;
if(v&&(!tail||(isIn?v>tail.best.amountOut:v<tail.best.amountIn)))tail=y;
}
if(my!==seq)return;
const v4q=await v4Job;
let v4c=null;
if(v4q&&v4q.amountOut>0n){
const v4Min=v4q.amountOut-(v4q.amountOut*slipBps)/10000n;
const p=v4q.pool;
v4c={best:{source:4,amountIn:v4q.amountIn,amountOut:v4q.amountOut,feeBps:p.fee>=8388608n?0n:BigInt(p.fee)/100n},
callData:"0x"+SEL_V4SWAP+encPoolKey(p)+encBool(p.zeroForOne)+encUint(v4q.amountIn)
+encUint(v4Min)+encAddr(rcv||acct||ZERO)+encUint(deadline),
fundedCallData:null,amountLimit:v4Min,msgValue:f.addr===ZERO?swapAmt:0n,
to:V4PORT,spender:f.addr===ZERO?null:V4PORT};
if(!r)r=v4c;
}
const pq=await preJob;
if(my!==seq)return;
let pc=null;
if(pq&&pq.out>0n){
const pMin=pq.out-(pq.out*slipBps)/10000n;
const pNative=pq.tokenIn===ZERO;
const pWethIn=pNative&&(pq.unwrap||0n)>0n;
const pTo=rcv||acct||ZERO;
const pFund=pWethIn?WETH:pq.tokenIn;
const routeData=pWethIn
?encPRouteWeth(pq.pools,pq.tokenOut,swapAmt,pMin,pTo)
:encPRoute(pq.pools,pq.tokenIn,pq.tokenOut,swapAmt,pMin,pTo);
const routedLeg=encSnwap(pFund,swapAmt,pTo,pq.tokenOut,pMin,PROUTE,routeData);
const checkpointLeg=encSnwap(ZERO,0n,acct||ZERO,ZERO,0n,PROUTE,
"0x"+SEL_PCHECKPOINT+encAddr(pFund)+strip0x(keccak(hexToBytes(routeData)))+encAddr(acct||ZERO));
const pCall=(pNative&&!pWethIn)?routedLeg:encCalls([checkpointLeg,routedLeg]);
const pFunded=(pNative&&!pWethIn)?null:encCalls([
checkpointLeg,
encSweep(pFund,swapAmt,PROUTE),
encSnwap(ZERO,0n,pTo,pq.tokenOut,pMin,PROUTE,routeData),
]);
pc={best:{source:SRC_PRECISION,amountIn:swapAmt,amountOut:pq.out,feeBps:pq.fee/100n},
callData:pCall,
fundedCallData:pFunded,amountLimit:pMin,msgValue:(pNative&&!pWethIn)?swapAmt:0n,
wrap:pq.wrap||0n,outDiffers:!!pq.outDiffers,poolOut:pq.tokenOut,
to:null,spender:(pNative&&!pWethIn)?null:ZROUTER,pools:pq.pools};
if(!r)r=pc;
}
if(!r&&curveOnlyOut)throw Object.assign(Error(`exact-output is unavailable for this pair — enter an amount to PAY instead`),{exactOut:1});
if(!r)throw Error("bad quote");
if(r.best.amountIn<=0n||r.best.amountOut<=0n||(!isIn&&r.amountLimit<r.best.amountIn))throw Error("bad quote");
let dc=null;
if(isIn&&CHAIN_ID===4663&&f.addr!==ZERO&&t.addr!==ZERO){
const dq=await deepQuote(f.addr,t.addr,swapAmt,r&&r.best?r.best.amountOut:0n);
if(my!==seq)return;
if(dq&&dq.out>0n){
const dMin=dq.out-(dq.out*slipBps)/10000n;
const dTo=rcv||acct||ZERO;
const leg="0x"+SEL_SWAPDEEP+encAddr(dTo)+encAddr(dq.t0)+encAddr(dq.t1)+encUint(dq.epoch)
+strip0x(dq.order)+encUint(dq.isBid?1:0)+encUint(swapAmt)+encUint(dMin)+encUint(deadline);
dc={best:{source:SRC_DEEP,amountIn:dq.inUsed,amountOut:dq.out,feeBps:0n},
callData:encCalls([leg,encSweep(f.addr,0n,dTo)]),
fundedCallData:null,amountLimit:dMin,msgValue:0n,
wrap:0n,outDiffers:false,poolOut:t.addr,to:null,spender:ZROUTER};
}
}
for(const c of [v4c,pc,dc]){
if(!c||c===r)continue;
if(isIn?c.best.amountOut>r.best.amountOut:c.best.amountIn<r.best.amountIn)r=c;
}
let hybrid=null,bookIncomplete=false,bookUnavailable=false,plannerBounded=false,rank=null;
if(acct){
const candidates=await candJob;
bookIncomplete=!!candidates.incomplete;
bookUnavailable=!!candidates.unavailable;
if(my!==seq)return;
const quoteRem=async(x,eo)=>{
const qs=[],groups=[],add=(sel,data,u,v,S,sb)=>{
qs.push({data:"0x"+sel+data,u,v,S,sb});return qs.length-1};
const z0=encBool(eo)+encAddr(f.addr)+encAddr(t.addr)+encUint(x)+encUint(0n)+encUint(deadline);
const zs=encBool(eo)+encAddr(f.addr)+encAddr(t.addr)+encUint(x)+encUint(slipBps)+encUint(deadline);
groups.push([add("e453166e",a+rf+z0,4,9),add("e453166e",a+rf+zs,4,9)]);
groups.push([add("4c464f59",a+z0,8,13),add("4c464f59",a+zs,8,13)]);
if(!eo){
const w=slipBps*3n,ss=w<150n?150n:w>500n?500n:w;
const ps=encAddr(f.addr)+encAddr(t.addr)+encUint(x)+encUint(ss)+encUint(deadline);
for(const sel of["892af013","85f86a90"])groups.push([add(sel,a+ps,4,8,1,ss)]);
}
const raw=await mc3Deep(qs.map(q=>({to:ZQUOTER,data:q.data})),quoteBlock);
const ds=qs.map((q,i)=>{try{return raw[i]?decQ(raw[i],q.sb||slipBps,eo,q.u,q.v,q.S):null}catch{return null}});
let best=null;
for(const g of groups){
const y=g.length>1?merge(ds[g[0]],ds[g[1]]):ds[g[0]];
if(!y)continue;
if(eo&&y.sources&&y.sources.includes(SRC_CURVE))continue;
const v=eo?y.best.amountIn:y.best.amountOut;
if(v&&(!best||(eo?v<best.best.amountIn:v>best.best.amountOut)))best=y;
}
return best;
};
const gasValue=async wei=>{
const token=isIn?t.addr:f.addr;
if(token===ZERO||token.toLowerCase()===WETH.toLowerCase())return wei;
const eo=!isIn,ti=isIn?ZERO:token,to=isIn?token:ZERO;
const z=encBool(eo)+encAddr(ti)+encAddr(to)+encUint(wei)+encUint(0n)+encUint(deadline);
try{
const raw=await rpc(C,[{to:ZQUOTER,data:"0xe453166e"+a+rf+z},quoteBlock]);
const q=decQ(raw,0n,eo,4,9);
const v=isIn?q.best.amountOut:q.best.amountIn;
if(v>0n)return v;
}catch{}
const ethSide=f.addr===ZERO||f.addr.toLowerCase()===WETH.toLowerCase();
const tokSide=t.addr===ZERO||t.addr.toLowerCase()===WETH.toLowerCase();
const inA=r.best.amountIn,outA=r.best.amountOut;
if(inA>0n&&outA>0n){
if(isIn&ðSide)return wei*outA/inA;
if(!isIn&&tokSide)return wei*inA/outA;
}
return null;
};
const tailDelta=swapAmt-tailAmt;
const tailFits=!!tail&&r===zr;
const seedOut=isIn&&tailFits&&r.best.amountOut>tail.best.amountOut
?r.best.amountOut-tail.best.amountOut:r.best.amountOut;
const seedIn=!isIn&&tailFits&&r.best.amountIn>tail.best.amountIn
?r.best.amountIn-tail.best.amountIn:r.best.amountIn;
let p=isIn
?planBookExactIn(candidates,swapAmt,seedOut,tailFits&&seedOut!==r.best.amountOut?tailDelta:r.best.amountIn)
:planBookExactOut(candidates,swapAmt,seedIn,tailFits&&seedIn!==r.best.amountIn?tailDelta:r.best.amountOut);
plannerBounded=!!(p&&p.bounded);
let amm=null,ammFor=null;
for(let round=0;p&&(isIn?p.ammIn:p.ammOut)&&round<2;round++){
const rem=isIn?p.ammIn:p.ammOut;
amm=await quoteRem(rem,!isIn).catch(()=>null);ammFor=rem;
if(!amm)break;
const next=isIn
?planBookExactIn(candidates,swapAmt,amm.best.amountOut,rem)
:planBookExactOut(candida