0x68575b07…67c7·#25,914,175·view on Etherscan
tes,swapAmt,amm.best.amountIn,rem);
if(!next){p=null;break}
const stable=(isIn?next.ammIn===p.ammIn:next.ammOut===p.ammOut);
p=next;plannerBounded=plannerBounded||!!p.bounded;if(stable)break;
}
if(p){
const rem=isIn?p.ammIn:p.ammOut;
if(!rem)amm=null;
else if(!(amm&&ammFor===rem))amm=await quoteRem(rem,!isIn).catch(()=>null);
if(amm&&!bolOk(amm.callData))amm=null;
if(!rem||amm){
const recipient=rcv||acct;
const ammBudget=amm?(isIn?rem:amm.amountLimit):0n;
const totalBudget=p.bookIn+ammBudget;
const expectedIn=p.bookIn+(amm?amm.best.amountIn:0n);
const expectedOut=p.bookOut+(amm?amm.best.amountOut:0n);
const saving=isIn
?(expectedOut>r.best.amountOut?expectedOut-r.best.amountOut:0n)
:(expectedIn<r.best.amountIn?r.best.amountIn-expectedIn:0n);
let gasFloor=null;
if(saving){
const gasPrice=await gasPriceJob;
if(gasPrice){
const extraWei=gasPrice*(120000n+105000n*BigInt(p.fills.length));
gasFloor=await gasValue(extraWei);
}
}
const pricedGas=gasFloor!==null&&gasFloor>0n;
const wins=saving>0n&&pricedGas&&saving*10n>gasFloor*12n;
if(my!==seq)return;
if(wins){
const fp=encFillPlanAndSwap(
p.fills,f.addr,t.addr,recipient,acct,deadline,ammBudget,amm?amm.callData:"0x"
);
const minOut=isIn?p.bookOut+(amm?amm.amountLimit:0n):swapAmt;
const snwapIn=totalBudget===0n?ZERO:f.addr;
const planCall=encSnwap(snwapIn,totalBudget,recipient,t.addr,minOut,SWAPBOL,fp);
const callData=f.addr===ZERO?planCall:encCalls([
encCheckpoint(SWAPBOL,f.addr,acct),planCall
]);
let fundedCallData=null;
if(f.addr!==ZERO){
fundedCallData=encPermit2Hybrid(
amm?amm.callData:"0x",p.fills,f.addr,t.addr,recipient,acct,deadline,p.bookIn,p.bookOut
);
}
r={...r,best:{...r.best,amountIn:expectedIn,amountOut:expectedOut},callData,
fills:p.fills,pools:undefined,
fundedCallData,amountLimit:isIn?minOut:totalBudget,msgValue:f.addr===ZERO?totalBudget:0n,
slipBps:amm&&amm.slipBps,
to:null,spender:f.addr===ZERO?null:ZROUTER,
pool:null,wrap:0n,outDiffers:false,poolOut:undefined};
hybrid=isIn
?{bookIn:p.bookIn,bookOut:p.bookOut,ammIn:p.ammIn}
:{bookIn:p.bookIn,bookOut:p.bookOut,ammOut:p.ammOut};
plannerBounded=plannerBounded||!!p.bounded;
}
}
}
}
const pin=lanePin();
if(!isIn&&r&&r.amountLimit>0n){
try{
await loadSolvers();
const lanes=(solverLanes||[]).filter(x=>!laneDown(x.name)&&SOLVER_SHAPES_OUT[x.name]);
if(lanes.length&&solverFill&&solverExec){
const dl=new Promise(res=>setTimeout(()=>res(null),SOLVER_DEADLINE));
const ck=`o|${f.addr}|${t.addr}|${swapAmt}|${slipBps}`;
const tried=await Promise.all(lanes.map(x=>Promise.race([
laneCached(`${x.name}|${ck}`,
()=>SOLVER_SHAPES_OUT[x.name](x.endpoint,f.addr,t.addr,swapAmt,Number(slipBps),SOLVER_DEADLINE,f.dec,t.dec))
.then(q=>q?{...q,lane:x}:null).catch(()=>null),dl])));
const laneCeil=c=>{const d=c.inp+(c.inp*slipBps)/10000n;
return c.cap&&c.cap>0n?bmin(c.cap,d):d};
const chainCeil=r.amountLimit;
let win=null;
for(const c of tried){
if(!laneOk(c)||!c.inp)continue;
const ceil=laneCeil(c);
if(pin){
if(c.lane.name!==pin)continue;
win={...c,ceil,forced:1};break;
}
if(ceil*(10000n+c.lane.handicapBps)>=chainCeil*10000n)continue;
if(!win||ceil<win.ceil)win={...c,ceil};
}
rank=[{n:"On-chain",f:chainCeil}];
for(const c of tried){
if(!laneOk(c)||!c.inp)continue;
rank.push({n:c.lane.name,f:laneCeil(c)});
}
rank.sort((a,b)=>a.f>b.f?1:a.f<b.f?-1:0);
if(my!==seq)return;
if(win){
const ethIn=f.addr===ZERO;
r={best:{source:SRC_SOLVER,amountIn:win.inp,amountOut:swapAmt,feeBps:0n,
lane:win.lane.name,forced:win.forced},
callData:"0x"+SEL_FILL+encAddr(win.target)+encAddr(win.spender)+encAddr(f.addr)
+encUint(win.ceil)+encAddr(t.addr)+encUint(swapAmt)+encAddr(rcv||acct||ZERO)
+encUint(256n)+encUint(BigInt(strip0x(win.data).length/2))
+strip0x(win.data)+"0".repeat((64-(strip0x(win.data).length%64))%64),
fundedCallData:null,amountLimit:win.ceil,
msgValue:ethIn?win.ceil:0n,
to:solverFill,spender:ethIn?null:solverFill};
hybrid=null;
}
}
}catch{}
}
const pin2=lanePin();
if(isIn&&r&&r.amountLimit>0n){
try{
await loadSolvers();
const lanes=(solverLanes||[]).filter(x=>!laneDown(x.name));
if(lanes.length&&solverFill&&solverExec){
const deadline_=new Promise(res=>setTimeout(()=>res(null),SOLVER_DEADLINE));
const ck=`${f.addr}|${t.addr}|${swapAmt}|${slipBps}`;
const tried=await Promise.all(lanes.map(x=>Promise.race([
laneCached(`${x.name}|${ck}`,
()=>SOLVER_SHAPES[x.name](x.endpoint,f.addr,t.addr,swapAmt,Number(slipBps),SOLVER_DEADLINE,f.dec,t.dec))
.then(q=>q?{...q,lane:x}:null).catch(()=>null),
deadline_])));
const chainFloor=r.amountLimit;
let win=null;
for(const c of tried){
if(!laneOk(c)||!c.out)continue;
const floor=c.out-(c.out*slipBps)/10000n;
if(pin2){
if(c.lane.name!==pin2)continue;
win={...c,floor,forced:1};
break;
}
if(floor*10000n<=chainFloor*(10000n+c.lane.handicapBps))continue;
if(!win||floor>win.floor)win={...c,floor};
}
rank=[{n:"On-chain",f:chainFloor}];
for(const c of tried){
if(!laneOk(c)||!c.out)continue;
rank.push({n:c.lane.name,f:c.out-(c.out*slipBps)/10000n});
}
rank.sort((a,b)=>a.f<b.f?1:a.f>b.f?-1:0);
if(my!==seq)return;
if(win){
const ethIn=f.addr===ZERO;
r={best:{source:SRC_SOLVER,amountIn:swapAmt,amountOut:win.out,feeBps:0n,lane:win.lane.name,forced:win.forced},
callData:"0x"+SEL_FILL+encAddr(win.target)+encAddr(win.spender)+encAddr(f.addr)
+encUint(swapAmt)+encAddr(t.addr)+encUint(win.floor)+encAddr(rcv||acct||ZERO)
+encUint(256n)+encUint(BigInt(strip0x(win.data).length/2))
+strip0x(win.data)+"0".repeat((64-(strip0x(win.data).length%64))%64),
fundedCallData:null,amountLimit:win.floor,
msgValue:ethIn?swapAmt:0n,
to:solverFill,spender:ethIn?null:solverFill};
hybrid=null;
}
}
}catch{}
}
if(my!==seq)return;
const finalIn=r.best.amountIn;
const finalOut=r.best.amountOut;
if(isIn){outAmt.value=trimAmt(finalOut,t.dec);fitFont(outAmt)}
else{amt.value=trimAmt(finalIn,f.dec);fitFont(amt)}
const rx=(+formatUnits(finalOut,t.dec))/(+formatUnits(finalIn,f.dec));
const s=r.best.source,raw=s===SRC_DEEP?"Deepstate":SOURCES[s]||"?";
const src=r.best.source===SRC_SOLVER?`${r.best.lane} solver${r.best.forced?" \u00b7 pinned":""}`:hybrid?bookShare(hybrid,raw):(s===3||s===4||s===SRC_PRECISION)&&r.best.feeBps?`${raw}\u00a0${Number(r.best.feeBps)/100}%`:raw;
rate.textContent=isFinite(rx)?`1 ${f.sym} ≈ ${rx>=1?rx.toLocaleString("en-US",{maximumFractionDigits:4}):rx.toPrecision(4)} ${t.sym} · ${src}`:"";
rankBox.textContent="";
if(rank&&rank.length>1){
const top=rank[0].f;
const worse=isIn?"-":"+";
const used=r.best.source===SRC_SOLVER?r.best.lane:"On-chain";
for(const x of rank){
const row=document.createElement("i");
if(x.n===used)row.className="w";
const pinNow=lanePin();
if(x.n===pinNow)row.className+=" pin";
row.title=x.n===pinNow?"Pinned \u2014 click again for the best floor"
:x.f===top&&x.n!==used?"Best floor \u2014 click to use it":"Use this venue";
const pick=()=>{const on=lanePin()===x.n;laneOverride=on?null:x.n;laneOverrideFor=on?"":laneScope();update()};
row.onclick=pick;
row.setAttribute("role","button");
row.tabIndex=0;
row.onkeydown=e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();pick()}};
const n=document.createElement("span");
n.textContent=safeSym(x.n).slice(0,16);
const v=document.createElement("u");
const gap=top>0n?Number((x.f>top?x.f-top:top-x.f)*10000n/top)/100:0;
v.textContent=`${sigAmt(x.f,isIn?t.dec:f.dec)}${gap>0.004?` \u00b7 ${worse}${gap.toFixed(2)}%`:""}`;
row.append(n,v);
rankBox.appendChild(row);
}
}
rankBox.classList.toggle("hide",!(rankOpen&&rankBox.firstChild));
const paysSym=r.poolOut===ZERO?"ETH":"WETH";
rcvHdr.textContent=r.outDiffers?`You receive \u2014 as ${paysSym}`:"You receive";
if(r.outDiffers&&rate.textContent)rate.textContent+=` \u00b7 pays ${paysSym}`;
rate.title="";
if(venueLost||mcGaveUp>gaveUp0||(mcFailed>failed0&&mcOk===ok0))
rate.textContent+=" \u00b7 some venues unreachable";
if(isIn)rate.textContent+=` · Min ${trimAmt(r.amountLimit,t.dec)} ${t.sym}`;
else{
const exactMax=formatUnits(r.amountLimit,f.dec);
rate.textContent+=` · Max ${maxAmt(r.amountLimit,f.dec)} ${f.sym}`;
rate.title=`Exact maximum: ${exactMax} ${f.sym}`;
}
if(r.slipBps>slipBps)rate.textContent+=` · Split — bound widened to ${Number(r.slipBps)/100}%`;
if(bookIncomplete)rate.textContent+=" · Book scan capped";
if(plannerBounded)rate.textContent+=" · Book split approximate";
if(bookUnavailable)rate.textContent+=" · AMM only (books offline)";
if(pq&&pq.capped)rate.textContent+=` · Precision scan capped (${LQ_SCAN})`;
if(isIn&&f.launched&&(t.addr===ZERO||t.addr.toLowerCase()===WETH.toLowerCase())){
const floorOut=await quoteFloor(f.addr,swapAmt,quoteBlock);
if(my!==seq)return;
if(floorOut>0n){
if(floorOut>finalOut){
rate.textContent+=` \u00b7 Floor pays more: ${trimAmt(floorOut,18)} ETH`;
rate.title=`This coin can be burned back to the launcher for its share of the ether `
+`locked in its pool - ${trimAmt(floorOut,18)} ETH, against ${trimAmt(finalOut,18)} from selling. `
+`Redeem through the launcher at ${PLAUNCH} to take the larger.`;
}else{
rate.textContent+=` \u00b7 Floor ${trimAmt(floorOut,18)} ETH`;
rate.title=`The ether backing this amount if it were redeemed instead of sold. `
+`Selling pays more right now.`;
}
}
}
let refQ=iRef>=0&&dec[iRef]?dec[iRef].best:null;
let refPair=null;
if(!refQ&&isIn&&pq&&pq.out>0n&&refAmt>0n){
try{
const small=await quotePrecision(f,t,refAmt,PROUTE,quoteBlock);
if(my!==seq)return;
if(small&&small.out>0n)refPair={amountOut:small.out};
}catch{}
}
if(my!==seq)return;
const impSrc=refQ||refPair;
const imp=impSrc?impactBps(isIn?finalOut:finalIn,isIn?impSrc.amountOut:impSrc.amountIn,!isIn):null;
const mkt=impSrc?(isIn?impSrc.amountOut:impSrc.amountIn)*REF_N:0n;
const lossTok=imp!==null&&mkt?(isIn?(mkt>finalOut?mkt-finalOut:0n):(finalIn>mkt?finalIn-mkt:0n)):0n;
if(imp!==null&&imp>=IMPACT_HIDE){
const pctTxt=(Number(imp)/100).toFixed(2);
rate.textContent+=` · Impact ${pctTxt}%`;
if(imp>=IMPACT_WARN)stat.textContent=`High price impact: ${pctTxt}% — about ${trimAmt(lossTok,isIn?t.dec:f.dec)} ${isIn?t.sym:f.sym} worse than the market rate.`;
}
if(rankBox.firstChild){
const car=document.createElement("span");
car.className="rk";
car.textContent="\u25be";
car.title="Compare venues";
car.setAttribute("role","button");
car.tabIndex=0;
car.setAttribute("aria-expanded",rankBox.classList.contains("hide")?"false":"true");
const carToggle=()=>{const shut=rankBox.classList.toggle("hide");
rankOpen=!shut;
car.setAttribute("aria-expanded",shut?"false":"true")};
car.onclick=carToggle;
car.onkeydown=e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();carToggle()}};
rate.appendChild(document.createTextNode(" "));
rate.appendChild(car);
}
const inApprove=isIn?swapAmt:r.msgValue||r.amountLimit;
const shownPay=amt.value,shownGet=outAmt.value;
if(acct)last={callData:r.callData,fundedCallData:r.fundedCallData,msgValue:r.msgValue,
limit:r.amountLimit,shownPay,shownGet,
to:r.to,spender:r.spender,
amountIn:inApprove,from:f,recipient:rcv||"",exp:Date.now()+QUOTE_TTL,impact:imp,
lossTok,lossSym:isIn?t.sym:f.sym,lossDec:isIn?t.dec:f.dec,
fills:r.fills||null,tokenIn:f.addr,tokenOut:t.addr,
source:r.best.source,
wrap:r.wrap||0n,pools:r.pools||null,
mkt,got:isIn?finalOut:finalIn,isIn};
quoting=false;
render();
}catch(e){if(my===seq){
quoting=false;
const transport=!!e?.noWallet||mcGaveUp>gaveUp0||(mcFailed>failed0&&mcOk===ok0);
if(!transport&&!e?.exactOut&&advancePastDeadPair()){loadChart();update();return}
outEl.value="";fitFont(outEl);rankBox.textContent="";rankBox.classList.add("hide");render();
stat.textContent=e?.noWallet?NO_WALLET
:e&&e.exactOut?e.message
:transport
?"Your RPC could not complete the quote — some venues were never asked. Try again, or switch networks in your wallet and back."
:"No route: "+(e.message||e)}}
}
let debounceT=0;
const showNet=()=>{
const e=document.getElementById("net");
if(!e)return;
const c=chainCfg();
e.innerHTML=(c.icon||"")+"<span>"+c.short+"</span>";
e.title="Network: "+c.name+" — click to switch";
};
const switchNet=async()=>{
const ids=Object.keys(CHAINS).map(Number);
const next=ids[(ids.indexOf(CHAIN_ID)+1)%ids.length];
if(!prov()){setChain(next);showNet();location.reload();return}
try{
await rpc("wallet_switchEthereumChain",[{chainId:"0x"+next.toString(16)}]);
}catch(e){
if(e&&e.code===4902){
const c=CHAINS[next];
try{await rpc("wallet_addEthereumChain",[{chainId:"0x"+next.toString(16),chainName:c.name,
nativeCurrency:{name:"Ether",symbol:"ETH",decimals:18},rpcUrls:c.rpcs,blockExplorerUrls:[c.explorer]}])}catch{return}
}else return;
}
setChain(next);showNet();location.reload();
};
const DEEPSTATE="0x6cf19308c22fc82ea620fa0b3e94948d20f27b96";
const SEL_POOLID="1338aa1d",SEL_POOLEPOCH="8fa79763",SEL_SWAPDEEP="ad33b1d0";
const OZ20="52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00";
const DEEP_TAKER="0x00000000000000000000000000000000deeb0000";
const MAXU=(1n<<256n)-1n;
const slotKey=(k,sl)=>strip0x(keccak(hexToBytes(k+sl)));
const deepSlots={};
const findSlot=async(tok,sel,keyw,probe)=>{
const ck=tok+sel;
if(deepSlots[ck]!==undefined)return deepSlots[ck];
const cands=[OZ20,(BigInt("0x"+OZ20)+1n).toString(16).padStart(64,"0")];
for(let i=0;i<10;i++)cands.push(encUint(i));
for(const c of cands){
const sl=keyw.length>64?slotKey(keyw.slice(64),slotKey(keyw.slice(0,64),c)):slotKey(keyw,c);
try{
const got=await rpc(C,[{to:tok,data:"0x"+sel+keyw},L,{[tok]:{stateDiff:{["0x"+sl]:"0x"+encUint(probe)}}}]);
if(BigInt(got||0)===probe){deepSlots[ck]=c;return c}
}catch{return null}
}
deepSlots[ck]=null;return null;
};
const deepQuote=async(fa,ta,amt,expOut)=>{
if(CHAIN_ID!==4663||!amt||fa===ZERO||ta===ZERO)return null;
const [t0,t1]=fa.toLowerCase()<ta.toLowerCase()?[fa,ta]:[ta,fa];
const isBid=ta.toLowerCase()===t0.toLowerCase();
try{
const pid=await rpc(C,[{to:DEEPSTATE,data:"0x"+SEL_POOLID+encAddr(t0)+encAddr(t1)},L]);
if(!pid||pid==="0x")return null;
const ep=await rpc(C,[{to:DEEPSTATE,data:"0x"+SEL_POOLEPOCH+strip0x(pid)},L]);
const epoch=BigInt(ep||0);
const bs=await findSlot(fa,"70a08231",encAddr(DEEP_TAKER),0x1234567n);
if(bs===null)return null;
const as=await findSlot(fa,"dd62ed3e",encAddr(DEEP_TAKER)+encAddr(ZROUTER),0x7654321n);
if(as===null)return null;
const ov={[fa]:{stateDiff:{
["0x"+slotKey(encAddr(DEEP_TAKER),bs)]:"0x"+encUint(amt),
["0x"+slotKey(encAddr(ZROUTER),slotKey(encAddr(DEEP_TAKER),as))]:"0x"+encUint(MAXU)}}};
const price=isBid?0x7fffffffn:0x80000000n;
const seed=isBid?(expOut||0n):amt;
if(seed<=0n)return null;
let best=null;
for(let q=seed*4n,n=0;n<5&&q>0n;q/=4n,n++){
const order="0x"+encUint((price<<224n)|((q&((1n<<160n)-1n))<<64n));
const data="0x"+SEL_SWAPDEEP+encAddr(DEEP_TAKER)+encAddr(t0)+encAddr(t1)+encUint(epoch)
+strip0x(order)+encUint(isBid?1:0)+encUint(amt)+encUint(0n)+encUint(MAXU);
try{
const r=await rpc(C,[{from:DEEP_TAKER,to:ZROUTER,data},L,ov]);
const b=strip0x(r||"");
if(b.length<128)continue;
const ai=BigInt("0x"+b.slice(0,64)),ao=BigInt("0x"+b.slice(64,128));
if(ao>0n&&(!best||ao>best.out))best={inUsed:ai,out:ao,t0,t1,isBid,epoch,order};
}catch{}
}
return best;
}catch{return null}
};
const showAddr=async()=>{const a=account,short=a.slice(0,6)+"..."+a.slice(-4);
addr.textContent=short;addr.title=a+" - click to disconnect";addr.classList.add("on");
addr.setAttribute("role","button");addr.tabIndex=0;
const n=await nameRev(a);if(n&&a===account)addr.textContent=n};
async function disconnect(){
sessionStorage.setItem("dc","1");
try{delete LS[WK]}catch{}
location.reload();
}
addr.onclick=()=>{account?disconnect():connect()}
net.onclick=()=>{switchNet()}
net.onkeydown=e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();switchNet()}}
showNet();;
addr.onkeydown=e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();account?disconnect():connect()}};
const AUTO_Q_MAX=5;
const updateSoon=()=>{clearTimeout(debounceT);debounceT=setTimeout(()=>{debounceT=0;update()},250)};
const setMode=m=>{++seq;quoting=false;mode=m;const o=m==="in"?outAmt:amt;o.value="";fitFont(o);last=null;sendReady=null;render()};
amt.addEventListener("input",()=>{
if(lqMode){fitFont(amt);lqPreviewSoon();return}
if(tab==="book"){fitFont(amt);render();return}setMode("in");fitFont(amt);updateSoon()});
outAmt.addEventListener("input",()=>{
if(lqMode){fitFont(outAmt);lqPreviewSoon();return}
if(tab==="book"){fitFont(outAmt);seedFloor();render();return}setMode("out");fitFont(outAmt);updateSoon()});
const slipWarn=()=>slip.classList.toggle("warn",+slip.value>=3);
if(LS.slip&&+LS.slip>=.01&&+LS.slip<=10)slip.value=LS.slip;
slipWarn();
slip.addEventListener("input",()=>{last=null;slipWarn();render();updateSoon()});
rc.addEventListener("input",()=>{
if(lnMode)return;
if(lqMode){clearTimeout(lqToT);lqToT=setTimeout(lqShowTo,300);return}
last=null;sendReady=null;render();updateSoon()});
let lqToT;
const onEnter=e=>{
if(e.key!=="Enter")return;
const go=lnMode?lnGo:swap;
if(!go||go.classList.contains("hide"))return;
e.preventDefault();
if(debounceT){clearTimeout(debounceT);debounceT=0;update();return}
if(!go.disabled)go.click();
};
for(const el of[amt,outAmt,rc,slip,floorAmt,nftId,lnName,lnSym,lnSupply,lnMcap,lnAlloc,lnGoal,lnDays])
if(el)el.addEventListener("keydown",onEnter);
slip.addEventListener("change",()=>{slip.value=Math.min(10,Math.max(.01,+slip.value||.5));slipWarn();LS.slip=slip.value});
for(const sel of [fromSel,toSel]){
sel.dataset.prev=sel.value;
sel.addEventListener("change",async()=>{
if(sel.value!=="__custom"){
sel.dataset.prev=sel.value;
sel.dataset.addr=TOKENS[sel.value]?.addr||"";
pairChosen=true;
syncDisabled(sel);
syncNftUI();
if(sel===fromSel)refreshBalance();else refreshBalance1();
loadChart();
if(tab==="book"&&bookRows.length)paintBook();
update();
return;
}
last=null;render();
const prev=sel.dataset.prev;
let a;
try{a=(prompt("Paste token address:")||"").trim()}
catch{sel.value=prev;syncDisabled();
stat.textContent="This browser blocked the address prompt — add the token with a #token=0x… link instead.";
return}
if(!a){sel.value=prev;update();return}
stat.textContent="Loading token...";
try{
const idx=await addCustomToken(a);
rebuild();
const otherSel=sel===fromSel?toSel:fromSel;
if(String(idx)===otherSel.value){otherSel.value=prev;otherSel.dataset.prev=prev}
sel.value=String(idx);
sel.dataset.prev=sel.value;
pairChosen=true;
stat.textContent="";
syncDisabled(sel);syncNftUI();
refreshBalance();
update();
}catch(e){
const msg="Couldn't load token: "+(e.message||e);
sel.value=prev;
syncDisabled();syncNftUI();refreshBalance();update();
stat.textContent=msg;
}
});
}
flip.onclick=()=>{pairChosen=true;const a=fromSel.value,b=toSel.value,v=outAmt.value.replace(/,/g,"");fromSel.value=b;toSel.value=a;
amt.value=(v&&!isNaN(+v))?v:"";setMode("in");fitFont(amt);syncDisabled();syncNftUI();refreshBalance();loadChart();update()};
const sameAcct=(a,b)=>!!a&&!!b&&a.toLowerCase()===b.toLowerCase();
const wkBind=eth=>{
if(!eth||eth.__zb)return;
eth.__zb=1;
eth.on?.("chainChanged",cid=>{if(connecting)return;if(CHAINS[+cid]&&account){setChain(+cid);location.reload();return}location.reload()});
eth.on?.("accountsChanged",accs=>{if(connecting||sameAcct(accs?.[0],account))return;location.reload()});
};
const wireWallet=eth=>{
if(!eth||wireWallet.done)return;
wireWallet.done=true;
wkBind(eth);
(async()=>{
try{
const cid=await rpc(I,[]);
wireWallet.probed=1;
const hop=!!CHAINS[+cid]&&+cid!==CHAIN_ID;
if(hop){setChain(+cid);showNet();loadEthUsd();burnTotal()}
const accs=sessionStorage.getItem("dc")?[]:await rpc("eth_accounts",[]);
if(accs[0]&&CHAINS[+cid]){account=accs[0];showAddr()}
if(account||hop){
const keep2=pairAddrs();
await loadTokenList();
adoptList(keep2);
if(hop&&location.hash.length>1)applyLink();
refreshBalance();update();if(account)loadPos();syncChart();
}
}catch{}
})();
(async()=>{
const self=selfFromUrl()||ZSWAP_SELF;
if(!self)return;
try{
if(+(await rpc(I,[]))!==CHAIN_ID)return;
const ret=strip0x(await rpc(C,[{to:self,data:"0x"+SEL_LATEST},L])||"");
if(ret.length!==64)return;
let tip="0x"+ret.slice(24);
const me=self.toLowerCase();
if(BigInt(tip)===0n||tip===me)return;
const rd=async(to,sel)=>{const h=strip0x(await rpc(C,[{to,data:"0x"+sel},L])||"");return h.length===64?h:""};
const now=Date.now()/1000;
for(let i=0;i<32&&tip!==me;i++){
const pv=await rd(tip,SEL_PREV);
if(!pv)break;
const prev="0x"+pv.slice(24);
if(BigInt(prev)===0n)break;
const at=await rd(prev,SEL_SUCCAT);
const born=at?Number(BigInt("0x"+at)):0;
if(!born||now>=born+MATURITY)break;
tip=prev;
}
if(tip===me)return;
const h=(location.hostname||"").split(".");
const url=/^0x[0-9a-fA-F]{40}$/.test(h[0]||"")
?`${location.protocol}//${[tip,...h.slice(1)].join(".")}/`
:`https://${tip}.w4eth.io/`;
footAddr.innerHTML+=` · <a href="${url}" target="_blank" rel="noopener" `
+`title="A newer version exists on chain. This page is unchanged and always will be; the link opens the successor.">newer →</a>`;
}catch{}
})();
};
const wkGo=()=>{wireWallet(prov());
if(!prov())window.addEventListener("ethereum#initialized",()=>wireWallet(prov()),{once:true})};
if(!PROV&&LS[WK]&&LS[WK]!=="wc")wkRestore().then(wkGo,wkGo);else wkGo();
setTimeout(burnTotal,0);
setTimeout(loadEthUsd,0);
const SEL_TRANSFER="a9059cbb";
let SB2=MB.sb;
let SB1=MB.s1;
const SBVIEW="0x000000E0b25449F32f7D9259aC449bA88E78dFCE";
let SWAPBOL=MB.sw;
let DUTCH=MB.du;
let ORDERBOL=MB.ob;
let FLOOR=MB.fl;
const FLOORVIEW="0x0000004E376e9dB5D9EC28E6711E1a64997C6ba7";
const SEL_NEXTID="2a58b330",SEL_NEXTID2="61b8ce8c",SEL_GETORDERS="03652027",SEL_CANCELORD="514fcac7",SEL_EXPIRED="d6c3de07",
SEL_WITHDRAW="ef3d3521",SEL_REPLACE="84343d3a";
const SEL_FILL1="c37dfc5b",SEL_FILL2="9d136c7f",SEL_FILL2_UNWRAP="3987baf4",SEL_FILL2_ETH="6f608bab";
const SEL_RECENT="6a9849c1",SEL_RECENT_DUTCH="98035c9a",SEL_DUTCH_FILL="ae7a8260",SEL_DUTCH_CANCEL="40e58ee5";
const SEL_CANCEL_UNWRAP="21dd76f9",SEL_DUTCH_CANCEL_UNWRAP="8382de65";
const SEL_DUTCH_LISTING="de74e57b";
const SEL_CANDS="5f452988",SEL_DUTCH_CANDS="eb33e466",SEL_FILLPLAN="c277f67c";
const SEL_FILLPLAN_SWAP="9090c8e5",SEL_SNWAP="5f3bd1c8";
const SEL_COLL_BIDS="16bb24eb";
const SEL_FLOOR_CANDS="c587d927",SEL_RECENT_FLOOR="a5edd13d";
const SEL_ORDER_FLOOR="23e93357";
const SEL_BOL_FLOOR="b732d224";
let floorReady=null;
async function floorRoutable(block){
if(FLOOR===ZERO||FLOORVIEW===ZERO)return false;
if(floorReady!==null)return floorReady;
try{
const h=await rpc(C,[{to:SWAPBOL,data:"0x"+SEL_BOL_FLOOR},block||L]);
floorReady=("0x"+strip0x(h).slice(-40)).toLowerCase()===FLOOR.toLowerCase();
}catch{return false}
return floorReady;
}
const SEL_BIDS="4423c5f1";
const SEL_INITIAL_B="878ea250",SEL_TOKENURI="c87b56dd",SEL_LOGOOF="6ce273ac";
const SEL_QUOTEFILL="f325beda";
async function preflightLeg(row,routeIn,routeOut,pay){
if(!row.floor)return preflightAsk(row,pay);
if(!await floorRoutable(L))throw Error("this executor cannot route bids yet");
const want=routeIn===ZERO?WETH:routeIn,gets=routeOut===ZERO?WETH:routeOut;
let h;
try{h=await rpc(C,[{to:FLOOR,data:"0x"+SEL_BIDS+encUint(row.id)},L])}
catch{throw Error("bid could not be read — refresh and retry")}
const at=i=>strip0x(h).slice(i*64,(i+1)*64);
if(strip0x(h).length<11*64)throw Error("bid could not be read — refre