0x68575b07…67c7·#25,913,258·view on Etherscan
data:"0x"+SEL_CREATOROF+encAddr(candidate)},L]);
if(c&&"0x"+strip0x(c).slice(24)===owner.toLowerCase())token=candidate;
}catch{}
}
if(token){
try{
const idx=await addCustomToken(token);
TOKENS[idx].launched=1;
rebuild();
fromSel.value=String(Math.max(0,TOKENS.findIndex(t=>t.addr===ZERO)));
fromSel.dataset.prev=fromSel.value;
toSel.value=String(idx);
toSel.dataset.prev=toSel.value;
pairChosen=true;
syncDisabled();syncNftUI();
refreshBalance();
update();
}catch{}
}
stat.innerHTML=token?`${safeSym(sym)} is live at `
+`<a href="${chainCfg().explorer}/token/${token}" target="_blank" rel="noreferrer">${short(token)}</a>`
+` \u00b7 0.4% of each trade goes to you \u2014 collect it from the coin panel`
:`${safeSym(sym)} is live \u00b7 0.4% of each trade goes to you`;
lnArtBytes=null;lnArtNote.textContent="none";lnArtNote.classList.remove("set");
lnPrev.classList.remove("set");lnArt.value="";
}catch(e){err(e)}
finally{lnGo.disabled=false}
};
const SEL_MARKETS="29c21083",SEL_TAPE="29a65241";
const SEL_BYCREATOR="7d78be2b",SEL_TOKEN1="d21220a7",SEL_BYCREATOR_N="aa5e6b5b",SEL_RESERVE0="443cb4bc",SEL_FEERECIP="46904840";
const LAUNCHED=[];
const LAUNCH_SHOW=24;
const LAUNCH_SCAN=256;
const FINE=300,COARSE=14400,TFS=[["5m",300],["1h",3600],["4h",14400],["1d",86400]];
const CH_POOLS=8;
const srcFor=tf=>tf>=COARSE?COARSE:FINE;
let chFloor=0,chSupply=0,chFloorKey="",chCoin1=0;
let chKind=LS.ck==="line"?"line":"candle",chInv=false,chInvKey="",chPeriod=300,chBars=null,chSeq=0,chPools=null,chOpen=LS.ch==="1",chCache={};
let chDraw=null;
const chKeep=(key,val)=>{
chCache[key]=val;
for(const k in chCache)if(k!==key&&Date.now()-chCache[k].at>60000)delete chCache[k];
};
const unf=p=>(p&0xffffff)*2**(p>>>24);
const decBar=w=>{if(!w)return null;const f=s=>Number((w>>BigInt(s))&0xffffffffn);
return{b:Number(w&0xffffffffn),o:unf(f(32)),h:unf(f(64)),l:unf(f(96)),c:unf(f(128)),v:unf(f(160)),n:Number((w>>192n)&0xffffn)}};
const rollUp=(bars,src,dst)=>{if(dst<=src)return bars.filter(Boolean);
const out=[];let g=null,k=null;
for(let i=bars.length-1;i>=0;i--){const b=bars[i];if(!b)continue;
const key=Math.floor(b.b*src/dst);
if(key!==k){if(g)out.push(g);k=key;g={b:key,o:b.o,h:b.h,l:b.l,c:b.c,v:b.v,n:b.n}}
else{g.h=Math.max(g.h,b.h);g.l=Math.min(g.l,b.l);g.c=b.c;g.v+=b.v;g.n+=b.n}}
if(g)out.push(g);return out.reverse()};
const CH_WICK_SHARE=.01;
const mergeTapes=tapes=>{const m=new Map();
for(const bars of tapes)for(const b of bars||[]){if(!b)continue;
let e=m.get(b.b);
if(!e)m.set(b.b,e={b:b.b,v:0,n:0,ov:0,cv:0,parts:[]});
e.v+=b.v;e.n+=b.n;e.ov+=b.o*b.v;e.cv+=b.c*b.v;e.parts.push(b)}
const out=[...m.values()].sort((x,y)=>y.b-x.b);
for(const e of out){
const big=e.v>0?e.parts.filter(x=>x.v>=e.v*CH_WICK_SHARE):[];
const src=big.length?big:e.parts;
let h=-Infinity,l=Infinity;
for(const x of src){if(x.h>h)h=x.h;if(x.l<l)l=x.l}
e.h=h;e.l=l;
if(e.v>0){e.o=e.ov/e.v;e.c=e.cv/e.v}else{e.o=src[0].o;e.c=src[0].c}
delete e.ov;delete e.cv;delete e.parts}
return out};
const chPair=()=>{const f=TOKENS[fromSel.value],t=TOKENS[toSel.value];
if(!f||!t||f.addr===t.addr)return null;
return f.addr.toLowerCase()<t.addr.toLowerCase()?[f,t]:[t,f]};
let chLoading="";
async function loadChart(){
const p0=chPair();
const k0=chPairKey(p0);
if(k0&&chLoading===k0)return;
chBars=null;chPools=null;
const p=p0;
if(tab!=="swap"||!p){syncChartUI();return}
const my=++chSeq,key=k0;
const hit=chCache[key];
if(hit&&Date.now()-hit.at<30000){chBars=hit.bars;chPools=hit.pools;syncChartUI();return}
chLoading=key;
try{
if(PPLENS===ZERO||(await rpc("eth_getCode",[PPLENS,L])).length<5)return syncChartUI();
const marketsFor=async pair=>{
const [raw]=await mc3([{to:PPLENS,data:"0x"+SEL_MARKETS+encAddr(pair[0].addr)+encAddr(pair[1].addr)
+encAddr(ZERO)+encUint(0)+encUint(LQ_SCAN)+encUint(0)}]);
const found=[];
if(raw){const h=strip0x(raw),n=Number(BigInt("0x"+h.slice(64,128))),base=128;
for(let i=0;i<n&&i<LQ_SCAN;i++){const at=k=>BigInt("0x"+h.slice(base+(i*PI_WORDS+k)*64,base+(i*PI_WORDS+k+1)*64));
if(at(PI_HOOK)!==0n||at(PI_LIQ)===0n)continue;
found.push({a:"0x"+h.slice(base+(i*PI_WORDS+PI_POOL)*64+24,base+(i*PI_WORDS+PI_POOL+1)*64),liq:at(PI_LIQ)})}}
found.sort((x,y)=>y.liq>x.liq?1:y.liq<x.liq?-1:0);
return found.slice(0,CH_POOLS).map(x=>x.a);
};
let eff=p,pools=await marketsFor(p);
if(my!==chSeq)return;
if(!pools.length){
const alt=chOtherForm(p);
if(alt){
const altPools=await marketsFor(alt);
if(my!==chSeq)return;
if(altPools.length){eff=alt;pools=altPools}
}
}
const [t0,t1]=eff;
if(!pools.length){chKeep(key,{at:Date.now(),bars:null,pools:null,pair:null});return syncChartUI()}
const reqs=[];
for(const a of pools)reqs.push({to:a,data:"0x"+SEL_TAPE+encUint(FINE)+encUint(256)},
{to:a,data:"0x"+SEL_TAPE+encUint(COARSE)+encUint(256)});
const tapes=await mc3Deep(reqs);
if(my!==chSeq)return;
const dec1Tape=hex=>{if(!hex)return null;
const h=strip0x(hex),n=Number(BigInt("0x"+h.slice(64,128))),bars=[];
for(let j=0;j<n;j++)bars.push(decBar(BigInt("0x"+h.slice(128+j*64,128+(j+1)*64))));
return bars};
const decoded=tapes.map(dec1Tape);
const fine=[],coarse=[];
for(let i=0;i<pools.length;i++){fine.push(decoded[i*2]);coarse.push(decoded[i*2+1])}
const sc=10**(t0.dec-t1.dec)/1e18;
const build=set=>{const m=mergeTapes(set);
for(const b of m){b.o*=sc;b.h*=sc;b.l*=sc;b.c*=sc}return m.length?m:null};
const f=build(fine);
let c=build(coarse);
if(f&&c){const lead=rollUp(f,FINE,COARSE).filter(b=>b.b>c[0].b);
if(lead.length)c=lead.concat(c)}
chBars=f||c?{[FINE]:f,[COARSE]:c}:null;
const live=set=>set.filter(d=>d&&d.some(Boolean)).length;
chPools=chBars?{[FINE]:live(fine),[COARSE]:live(coarse)}:null;
chKeep(key,{at:Date.now(),bars:chBars,pools:chPools,pair:eff===p?null:eff});
}catch{chBars=null;chPools=null}
finally{if(chLoading===k0)chLoading=""}
if(my===chSeq)syncChartUI();
}
const chPoolsAt=step=>chPools&&chPools[step]||0;
const chLabel=p=>chInv?`${p[0].sym} per ${p[1].sym}`:`${p[1].sym} per ${p[0].sym}`;
async function chFloorFor(p){
const key=chPairKey(p);
if(key===chFloorKey)return;
chFloorKey=key;chFloor=0;chSupply=0;chCoin1=0;
const tok=p&&p[1]&&p[1].launched?p[1].addr:p&&p[0]&&p[0].launched?p[0].addr:"";
if(!tok)return;
chCoin1=p[1]&&p[1].launched?1:0;
try{
const [fp,sup]=await mc3Deep([{to:PLAUNCH,data:"0x"+SEL_FLOORPRICE+encAddr(tok)},
{to:tok,data:"0x"+SEL_TOTALSUPPLY}]);
if(key!==chFloorKey)return;
chFloor=fp?+formatUnits(BigInt(fp),18):0;
chSupply=sup?+formatUnits(BigInt(sup),18):0;
}catch{}
}
function syncChartUI(){
const on=tab==="swap"&&!!chBars;
chTog.classList.toggle("hide",!on);
chBox.classList.toggle("hide",!on||!chOpen);
chTog.setAttribute("aria-expanded",on&&chOpen?"true":"false");
if(!on||!chOpen)return;
const p=chEff();
chNote.textContent=p?chLabel(p):"";
drawChart();syncInv();
}
const NUMERAIRES=new Set([
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
"0xdac17f958d2ee523a2206206994597c13d831ec7",
"0x6b175474e89094c44da98b954eedeac495271d0f",
]);
const moneyRank=a=>{a=(a||"").toLowerCase();
return NUMERAIRES.has(a)?2:(a===ZERO||a===WETH.toLowerCase())?1:0};
const chPairKey=p=>p?p[0].addr.toLowerCase()+":"+p[1].addr.toLowerCase():"";
const chNaturalInv=p=>!!p&&moneyRank(p[0].addr)>moneyRank(p[1].addr);
const chOtherForm=p=>{
const eth=p.filter(x=>isEthLike(x.addr));
if(eth.length!==1)return null;
const cur=eth[0],rest=p[0]===cur?p[1]:p[0];
const sub=TOKENS.find(x=>x.addr.toLowerCase()===(cur.addr===ZERO?WETH:ZERO).toLowerCase());
if(!sub)return null;
return sub.addr.toLowerCase()<rest.addr.toLowerCase()?[sub,rest]:[rest,sub];
};
const chEff=()=>{const p=chPair();if(!p)return p;
const hit=chCache[chPairKey(p)];
return (hit&&hit.pair)||p;};
const CH_SLOTS=Math.floor((340-2-42)/3),CH_FILL=.34;
const chFinest=()=>chBars&&chBars[FINE]?FINE:COARSE;
const chSeries=secs=>{
if(!chBars)return null;
const src=srcFor(secs),step=chBars[src]?src:chFinest(),base=chBars[step];
if(!base||!base.length)return null;
const per=Math.max(secs,step);
let pts=rollUp(base,step,per).slice().reverse();
pts=pts.map(b=>{const{o,c}=b;
if(!(o>0)||!(c>0)||!isFinite(o)||!isFinite(c))return null;
const h=b.h>0&&isFinite(b.h)?b.h:0,l=b.l>0&&isFinite(b.l)?b.l:Infinity;
return{...b,h:Math.max(h,o,c),l:Math.min(l,o,c)}}).filter(Boolean);
return pts.length?{pts,per,step}:null;
};
const chAutoPeriod=()=>{
if(!chBars)return null;
const fit=secs=>{const s=chSeries(secs);
if(!s||s.per!==secs)return null;
const pts=s.pts,newest=pts[pts.length-1].b;
const shown=pts.filter(b=>newest-b.b<CH_SLOTS);
if(!shown.length)return null;
const fill=shown.length/(newest-shown[0].b+1);
const whole=newest-pts[0].b+1<=CH_SLOTS;
return{score:shown.length*fill,ok:shown.length>=6&&fill>=CH_FILL&&whole}};
let best=null,bestS=-1;
for(const[,secs] of TFS){const f=fit(secs);
if(!f)continue;
if(f.ok)return secs;
if(f.score>bestS){best=secs;bestS=f.score}}
return best==null?chFinest():best;
};
let chTfKey="";
const chSyncPeriod=()=>{
const k=chPairKey(chEff());
if(k===chTfKey)return;
const auto=chAutoPeriod();
if(auto==null)return;
chTfKey=k;chPeriod=auto;
};
const chSyncTfs=()=>{
const finest=chFinest();
if(chPeriod<finest)chPeriod=finest;
for(const c of chTf.children){if(!c.dataset.secs)continue;
const secs=Number(c.dataset.secs);
c.disabled=!!chBars&&secs<finest;
c.title=c.disabled?"This pair has no five-minute tape to draw":"";
c.classList.toggle("on",secs===chPeriod)}
};
const chSyncOrientation=()=>{
const p=chEff(),k=chPairKey(p);
if(k===chInvKey)return;
chInvKey=k;chInv=chNaturalInv(p);
};
const hudFor=i=>{
if(!chDraw)return;
const{pts,num,UP,DN,ch,per,hd}=chDraw;
if(!hd)return;
if(i<0){const b=pts[pts.length-1];
let note="",flip="";
if(chInv&&isFinite(ch)&&ch>-100){
const other=(1/(1+ch/100)-1)*100;
const pr=chEff&&chEff();
const base=pr&&pr[0]?pr[0].sym:"the token";
note=` title="${safeSym(base)} is ${other>=0?"+":""}${other.toFixed(2)}% over this window. `
+`This chart prices the pair the other way up, so its line moves the opposite way."`;
flip=` <span class="chflip">${safeSym(base)} ${other>=0?"+":""}${other.toFixed(2)}%</span>`;
}
hd.innerHTML=`<b>${num(b.c)}</b> <span style="color:${ch>=0?UP:DN}"${note}>${ch>=0?"+":""}${ch.toFixed(2)}%</span>${flip}`;
return}
const b=pts[i],up=b.c>=b.o,d=new Date(b.b*per*1e3);
const when=per>=86400
?d.toLocaleDateString("en-US",{month:"short",day:"numeric"})
:d.toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",hour12:false});
hd.innerHTML=`<b style="color:${up?UP:DN}">${num(b.c)}</b> <span>${when}</span>`
+`<span class="ohlc">H ${num(b.h)} L ${num(b.l)} · ${b.n} trade${b.n===1?"":"s"}</span>`;
};
const chPoint=e=>{
if(!chDraw)return;
const r=chArt.getBoundingClientRect();
if(!r.width)return;
const{pts,W,PL,st,b0}=chDraw;
const x=(e.clientX-r.left)/r.width*W;
const at=b0+Math.round((x-PL)/st-.5);
let i=0,near=Infinity;
for(let j=0;j<pts.length;j++){const d=Math.abs(pts[j].b-at);
if(d<near){near=d;i=j}}
hudFor(i);
if(!chDraw.svg)return;
let el=chDraw.cross;
if(!el){
el=document.createElementNS("http://www.w3.org/2000/svg","line");
el.setAttribute("class","cross");
el.setAttribute("y1","0");el.setAttribute("y2","150");
el.setAttribute("stroke","currentColor");el.setAttribute("stroke-opacity",".35");
el.setAttribute("stroke-width",".8");
chDraw.svg.appendChild(el);chDraw.cross=el;
}
const cx=chDraw.X(i).toFixed(1);
el.setAttribute("x1",cx);el.setAttribute("x2",cx);
};
chArt.addEventListener("pointermove",chPoint);
chArt.addEventListener("pointerdown",chPoint);
chArt.addEventListener("pointerleave",()=>{
if(chDraw&&chDraw.cross){chDraw.cross.remove();chDraw.cross=null}
hudFor(-1)});
function drawChart(){
if(!chBars)return;
const W=340,H=150,PL=2,PR=42,PT=10,PB=14,VH=22;
const pw=W-PL-PR,ph=H-PT-PB-VH;
chSyncPeriod();chSyncOrientation();chSyncTfs();
const ser=chSeries(chPeriod);
if(!ser){chArt.innerHTML='<div class="msg">No trades in this window.</div>';chDraw=null;return}
const per=ser.per;
let pts=ser.pts;
const newest=pts[pts.length-1].b,cap=Math.floor(pw/3);
const kept=pts.filter(b=>newest-b.b<cap);
const clipped=kept.length<pts.length;
pts=kept;
if(chInv)pts=pts.map(b=>({...b,o:1/b.o,h:1/b.l,l:1/b.h,c:1/b.c}))
.filter(b=>isFinite(b.o)&&isFinite(b.h)&&isFinite(b.l)&&isFinite(b.c));
if(!pts.length){chArt.innerHTML='<div class="msg">No trades in this window.</div>';chDraw=null;return}
let hi=-Infinity,lo=Infinity,vm=0;
for(const b of pts){if(b.v>vm)vm=b.v}
if(chKind==="line"){
for(const b of pts){if(b.c>hi)hi=b.c;if(b.c<lo)lo=b.c}
}else{
let bh=-Infinity,bl=Infinity;
for(const b of pts){const t=Math.max(b.o,b.c),u=Math.min(b.o,b.c);
if(t>bh)bh=t;if(u<bl)bl=u}
const span=bh>bl?bh-bl:bh*.1;
const cutHi=Math.min(bh+span*CH_WICK_CAP,bh*2),
cutLo=Math.max(bl-span*CH_WICK_CAP,bl/2);
for(const b of pts){
const h=Math.min(b.h,cutHi),l=Math.max(b.l,cutLo);
if(h>hi)hi=h;if(l<lo)lo=l}
}
if(hi===lo){hi*=1.001;lo*=0.999}
const rawLo=lo;
let sp=hi-lo;hi+=sp*.09;
lo-=Math.min(sp*.09,rawLo>0?rawLo*.1:0);
if(lo<=0)lo=rawLo>0?rawLo*.9:0;
sp=hi-lo;
const n=pts.length,b0=pts[0].b,slots=pts[n-1].b-b0+1;
const st=pw/slots,bw=Math.max(1,Math.min(9,st*.68));
const X=i=>PL+st*(pts[i].b-b0+.5),Y=p=>PT+ph*(1-(p-lo)/sp),vt=PT+ph+6,VY=v=>vt+(VH-6)*(1-(vm?v/vm:0));
const num=v=>v>=1000?v.toLocaleString("en-US",{maximumFractionDigits:2}):v>=1?v.toFixed(3):fmtPx(v);
const UP="#16a34a",DN="#c33";
const p0=chEff(),lbl=p0?chLabel(p0):"Price";
let s=`<svg viewBox="0 0 ${W} ${H}" preserveAspectRatio="none" role="img" aria-label="${lbl}, ${n} bars, ${num(pts[n-1].c)} now, range ${num(lo)} to ${num(hi)}">`;
for(let g=0;g<=3;g++){const p=lo+sp*g/3,y=Y(p).toFixed(1);
s+=`<line x1="${PL}" y1="${y}" x2="${W-PR}" y2="${y}" stroke="currentColor" stroke-opacity=".1"/>`
+`<text x="${W-PR+4}" y="${(Y(p)+2.5).toFixed(1)}" font-size="7" fill="currentColor" fill-opacity=".5">${p>0?num(p):"0"}</text>`}
for(let i=0;i<n;i++){const b=pts[i],y=VY(b.v);
s+=`<rect x="${(X(i)-bw/2).toFixed(1)}" y="${y.toFixed(1)}" width="${bw.toFixed(1)}" height="${Math.max(.4,vt+VH-y).toFixed(1)}" fill="currentColor" fill-opacity=".18"/>`}
const chNum=p0&&(chCoin1?p0[0]:p0[1]);
const ethNum=!!chNum&&(chNum.addr===ZERO||chNum.addr===WETH);
const fl=chFloor>0&ðNum?(chCoin1?(chInv?chFloor:1/chFloor):(chInv?1/chFloor:chFloor)):0;
if(fl>0&&fl>=lo&&fl<=hi){
const fy=Y(fl).toFixed(1);
s+=`<line x1="${PL}" y1="${fy}" x2="${W-PR}" y2="${fy}" stroke="currentColor" stroke-opacity=".45" stroke-width=".7" stroke-dasharray="3 2"/>`
+`<text x="${PL+3}" y="${(Y(fl)-2.5).toFixed(1)}" font-size="6.5" fill="currentColor" fill-opacity=".6">floor</text>`;
}
const rise=pts[n-1].c>=pts[0].o;
if(chKind==="line"){
const d=pts.map((b,i)=>`${i?"L":"M"}${X(i).toFixed(1)} ${Y(b.c).toFixed(1)}`).join(" ");
const col=rise?UP:DN;
s+=`<path d="${d} L${X(n-1).toFixed(1)} ${(PT+ph).toFixed(1)} L${X(0).toFixed(1)} ${(PT+ph).toFixed(1)} Z" fill="${col}" fill-opacity=".1"/>`
+`<path d="${d}" fill="none" stroke="${col}" stroke-width="1.2" stroke-linejoin="round"/>`
+`<circle cx="${X(n-1).toFixed(1)}" cy="${Y(pts[n-1].c).toFixed(1)}" r="1.8" fill="${col}"/>`;
}else{
for(let i=0;i<n;i++){const b=pts[i],col=b.c>=b.o?UP:DN,x=X(i);
const t=Y(Math.max(b.o,b.c)),bo=Y(Math.min(b.o,b.c));
s+=`<line x1="${x.toFixed(1)}" y1="${Y(b.h).toFixed(1)}" x2="${x.toFixed(1)}" y2="${Y(b.l).toFixed(1)}" stroke="${col}" stroke-width=".8"/>`
+`<rect x="${(x-bw/2).toFixed(1)}" y="${t.toFixed(1)}" width="${bw.toFixed(1)}" height="${Math.max(.8,bo-t).toFixed(1)}" fill="${col}"/>`}
}
const spanS=(pts[n-1].b-pts[0].b+1)*per;
const tAt=b=>{const d=new Date(b*per*1000);
return spanS>129600?d.toLocaleDateString("en-US",{month:"short",day:"numeric"})
:d.toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",hour12:false})};
const ticks=n>=3?[[0,"start"],[n>>1,"middle"],[n-1,"end"]]:[[0,"start"],[n-1,"end"]];
const tLbl=ticks.map(([i])=>i>=0&&i<n?tAt(pts[i].b):"");
ticks.forEach(([i,anc],k)=>{if(i<0||i>=n)return;
if(anc==="middle"&&(tLbl[k]===tLbl[0]||tLbl[k]===tLbl[tLbl.length-1]))return;
s+=`<text x="${X(i).toFixed(1)}" y="${H-3.5}" font-size="6.5" text-anchor="${anc}" `
+`fill="currentColor" fill-opacity=".45">${tLbl[k]}</text>`});
s+="</svg>";
const last=pts[n-1],first=pts[0],ch=((last.c-first.o)/first.o)*100;
chArt.innerHTML=s+'<div class="hd"></div>';
chDraw={pts,X,W,PL,st,b0,num,UP,DN,ch,per,
hd:chArt.querySelector(".hd"),svg:chArt.querySelector("svg"),cross:null};
hudFor(-1);
const took=rel(Math.max(per,(slots-1)*per));
const np=chPoolsAt(ser.step);
const fine=(chBars&&chBars[chFinest()])||null;
const newestBar=fine?fine.find(b=>b&&b.c>0):null;
const latest=newestBar?newestBar.c:pts[n-1].c;
const canon=latest>0?1/latest:0;
const px=chCoin1?canon:latest;
const mcap=chSupply>0&&px>0?chSupply*px:0;
chNote.textContent=p0?[chLabel(p0),
mcap>0?`${mcap>=1000?Math.round(mcap).toLocaleString("en-US"):mcap.toFixed(mcap>=1?1:3)} ${ethNum?"ETH":chCoin1?p0[0].sym:p0[1].sym} mcap${
ethNum&ðUsd>0?` (${fmtUsd(mcap*ethUsd)})`:""}`:"",
`${np} pool${np===1?"":"s"}`,`${clipped?"last ":""}${took}`].filter(Boolean).join(" · "):"";
if(p0){const was=chFloor+":"+chSupply+":"+chCoin1;
chFloorFor(p0).then(()=>{if(chFloor+":"+chSupply+":"+chCoin1!==was)drawChart()});}
}
for(const[label,secs]of TFS){const b=document.createElement("button");
b.textContent=label;b.dataset.secs=String(secs);if(secs===chPeriod)b.className="on";
b.onclick=()=>{chPeriod=secs;chTfKey=chPairKey(chEff());drawChart()};
chTf.appendChild(b)}
const kindBtn=document.createElement("button");
kindBtn.className="chk";
const syncKind=()=>{kindBtn.textContent=chKind==="candle"?"Line":"Candle";
kindBtn.title=`Switch to ${kindBtn.textContent.toLowerCase()} chart`};
syncKind();
kindBtn.onclick=()=>{chKind=chKind==="candle"?"line":"candle";LS.ck=chKind;syncKind();drawChart()};
chTf.appendChild(kindBtn);
const invBtn=document.createElement("button");
invBtn.className="chk";
invBtn.textContent="⇅";
const syncInv=()=>{const p=chEff();
invBtn.title=p?`Price ${chInv?p[1].sym:p[0].sym} instead — currently ${chInv?p[0].sym:p[1].sym} per ${chInv?p[1].sym:p[0].sym}`:"Invert the price";
invBtn.setAttribute("aria-pressed",chInv?"true":"false")};
syncInv();
invBtn.onclick=()=>{chInv=!chInv;syncInv();drawChart()};
chTf.appendChild(invBtn);
const syncChart=()=>{chSyncOrientation();syncInv();loadChart()};
chTog.onclick=()=>{chOpen=!chOpen;LS.ch=chOpen?"1":"0";syncChartUI()};
const lsecs=v=>{const m=/^(\d+)([mhdw]?)$/.exec((v||"").trim());
return m?+m[1]*(m[2]=="d"?86400:m[2]=="h"?3600:m[2]=="w"?604800:m[2]=="m"?60:1):NaN};
const symAddr=x=>{const m=TOKENS.filter(t=>t.sym.toLowerCase()===x);
return m.length===1?m[0].addr.toLowerCase():""};
const ARCADE=".arcade.wei",SC_OWNER="6352211e",SC_TEXT="308e3386";
const scEl=document.getElementById("scEl");
let scSeq=0;
const scShow=async name=>{
const my=++scSeq;
const n=String(name||"").trim().toLowerCase();
if(!/^[a-z0-9-]{1,63}\.arcade\.wei$/.test(n)){scEl.classList.add("hide");return}
const lbl=n.slice(0,-ARCADE.length);
scEl.classList.remove("hide");
scEl.textContent="Reading "+n+"\u2026";
let owner="",rec="";
try{
const id=namehash(n);
const[o,t]=await cfgBatch([{to:WNS,data:"0x"+SC_OWNER+pad32(id)},
{to:WNS,data:"0x"+SC_TEXT+pad32(id)+encUint(64)+strTail("score")}]);
if(my!==scSeq)return;
const a="0x"+strip0x(o||"").slice(24);
if(!/^0x[0-9a-f]{40}$/i.test(a)||/^0x0{40}$/i.test(a))throw Error("gone");
owner=a;
try{rec=decStr(t)}catch{}
}catch{if(my===scSeq)scEl.textContent="No such name \u2014 "+n+" has never been minted.";return}
const m=/^(\d+)(?:-w(\d+))?-[0-9a-z]+$/.exec(lbl);
scEl.textContent="";
const b=document.createElement("b");b.textContent=n;scEl.appendChild(b);
const line=t=>{const d=document.createElement("div");d.textContent=t;scEl.appendChild(d);return d};
if(m)line(`Minted score ${(+m[1]).toLocaleString("en-US")}`+(m[2]?` \u00b7 reached wave ${m[2]}`:""));
else line("Not a score name \u2014 the label carries no run.");
line("Held by "+short(owner));
if(m)line("Anyone can mint a name with any number \u2014 this says it was claimed, not earned.").className="scw";
if(m&&rec&&rec!==m[1])line(`The score record now reads ${rec}, not ${m[1]} \u2014 the holder changed it.`).className="scw";
const go=document.createElement("button");go.type="button";go.textContent="Play invaders";
go.onclick=()=>{sBlip();invPlay()};
scEl.appendChild(go);
};
let lSeq=0,listReady=false;
const lkWrote=Object.create(null);
const lkKeep=(el,v)=>{const w=lkWrote[el.id];
if(el.value!==""&&el.value!==w&&(w!==undefined||el.type!=="select-one"))return false;
el.value=v;lkWrote[el.id]=v;return true;
};
async function applyLink(e){
const q=new URLSearchParams(location.hash.slice(1));
const my=++lSeq;
if(![...q.keys()].length){
if(e){
if(typeof amt!=="undefined"&&amt){amt.value="";fitFont(amt)}
if(typeof outAmt!=="undefined"&&outAmt){outAmt.value="";fitFont(outAmt)}
if(typeof rc!=="undefined"&&rc){rc.value="";rc.classList.remove("bad")}
if(typeof rcvEl!=="undefined"&&rcvEl)rcvEl.textContent="";
if(typeof scEl!=="undefined"&&scEl)scEl.classList.add("hide");
setMode("in");
last=null;
try{update()}catch{}
}
return;}
const wantChain=+q.get("chain")||0;
if(CHAINS[wantChain]&&wantChain!==CHAIN_ID){
if(prov()){if(wireWallet.probed)stat.textContent=`This link is for ${CHAINS[wantChain].name} \u2014 switch your wallet there to use it.`;return}
setChain(wantChain);showNet();await loadTokenList();if(my!==lSeq)return;
}
const at=a=>a?TOKENS.findIndex(t=>t.addr.toLowerCase()===a):-1;
const tok=async v=>{if(!v)return "";const x=v.trim().toLowerCase();
if(!/^0x[0-9a-f]{40}$/.test(x))return symAddr(x);
if(at(x)<0)try{await addCustomToken(x,0)}catch{}
return at(x)<0?"":x};
if(symAddr((q.get("token")||"").trim().toLowerCase())||symAddr((q.get("out")||"").trim().toLowerCase()))pairChosen=true;
const both=async()=>[await tok(q.get("token")),await tok(q.get("out"))];
let[fa,ta]=await both();
if(my!==lSeq)return;
if((fa&&at(fa)<0)||(ta&&at(ta)<0)){[fa,ta]=await both();if(my!==lSeq)return}
if(!listReady){
const named=["token","out"].map(k=>(q.get(k)||"").trim()).filter(Boolean);
if(named.some(v=>!/^0x[0-9a-f]{40}$/i.test(v)&&!symAddr(v.toLowerCase())))return;
}
const fi=at(fa),oi=at(ta);
if(fi>=0||oi>=0)pairChosen=true;
rebuild();
if(fi>=0){fromSel.value=fi;fromSel.dataset.prev=fromSel.value}
if(oi>=0&&oi!==fi){toSel.value=oi;toSel.dataset.prev=toSel.value}
if(q.get("score"))scShow(q.get("score"));else scEl.classList.add("hide");
const to=q.get("to"),lk=lsecs(q.get("lock")),want=q.get("tab"),n=q.get("amount");
const t=want==="swap"||want==="send"||want==="book"?want
:q.get("out")?"swap":(to||!isNaN(lk))?"send":tab;
if(fromSel.value===toSel.value){
const alt=String(TOKENS.findIndex((x,i)=>String(i)!==fromSel.value&&(t==="book"||x.std!=="nft")));
if(alt!=="-1"){if(oi>=0)fromSel.value=alt;else toSel.value=alt}
}
const rcMine=rc.value!==""&&rc.value!==lkWrote.rc;
const wantLq=q.get("lq")==="1";
const linkWantsCard=fi>=0||oi>=0||to||n||!isNaN(lk)||q.get("token")||q.get("out");
if(!wantLq&&lqMode&&linkWantsCard)lqSet(false);
if(linkWantsCard){if(lnMode)lnSet(false);if(wnMode)wnSet(false);if(pvMode)pvSet(false)}
setTab(t);
if(wantLq&&t==="swap"&&!lqMode)lqSet(true);
if(to&&!rcMine)lkKeep(rc,to);
if(!isNaN(lk)){const os=[...dly.options].map(x=>+x.value).sort((a,b)=>a-b);
const v=String(os.find(o=>o>=lk)??os[os.length-1]);
if(t==="book")bookD=v;else if(t==="send")sendD=v;
if(t!=="swap")lkKeep(dly,v)}
if(n&&/^\d*\.?\d+$/.test(n)){
if(q.get("exactOut")==="1"&&q.get("out")){if(lkKeep(outAmt,n)){setMode("out");fitFont(outAmt)}}
else{if(lkKeep(amt,n)){setMode("in");fitFont(amt)}}
}
refreshBalance();const upd=update();
loadChart();
if(t==="book")loadBook();
if(listReady){
const miss=["token","out"].map(k=>(q.get(k)||"").trim())
.filter(v=>v&&!/^0x[0-9a-f]{40}$/i.test(v)&&!symAddr(v.toLowerCase())).map(v=>v.slice(0,24));
if(miss.length){try{await upd}catch{}
if(my===lSeq)stat.textContent=`Couldn\u2019t find ${miss.join(" or ")} \