0xacfba7ce…4082·#25,784,647·view on Etherscan
spec of row.v.split(";")){
const p=spec.trim().split(":");
if(p.length!==5||p[0]!=="v1")continue;
const other=p[1]==="0"?ZERO:p[1];
const hooks=p[4]==="0"?ZERO:p[4];
if(!/^0x[0-9a-f]{40}$/i.test(other)||!/^0x[0-9a-f]{40}$/i.test(hooks))continue;
if(!/^\d{1,7}$/.test(p[2])||!/^\d{1,7}$/.test(p[3]))continue;
const fee=Number(p[2]),ts=Number(p[3]);
if(!Number.isInteger(fee)||!Number.isInteger(ts)||ts<1)continue;
if(other.toLowerCase()===tokenAddr.toLowerCase())continue;
const a=tokenAddr.toLowerCase(),b=other.toLowerCase();
const zeroFirst=BigInt(a)<BigInt(b);
out.push({c0:zeroFirst?tokenAddr:other,c1:zeroFirst?other:tokenAddr,fee,ts,hooks});
if(out.length===8)break;
}
return out;
}
function v4PoolsFor(f,t){
const fa=f.addr.toLowerCase(),ta=t.addr.toLowerCase();
const seen=new Set(),out=[];
for(const tok of [f,t])for(const p of (tok.v4||[])){
const c0=p.c0.toLowerCase(),c1=p.c1.toLowerCase();
if(!((c0===fa&&c1===ta)||(c0===ta&&c1===fa)))continue;
const id=`${c0}:${c1}:${p.fee}:${p.ts}:${p.hooks.toLowerCase()}`;
if(seen.has(id))continue;
seen.add(id);
out.push({...p,zeroForOne:c0===fa});
}
return out;
}
const encPoolKey=p=>encAddr(p.c0)+encAddr(p.c1)+encUint(p.fee)+encUint(p.ts)+encAddr(p.hooks);
const SEL_QUOTE_BEST="2adaa389",SEL_EFFFEE="ef66de32";
const PROUTE="0x0000007Be74558A1F8c9045301c6F44C8eD0c9eB";
const SEL_PROUTE="5d6498e1",SEL_PCHECKPOINT="0b7c6c6c";
const SEL_PROUTEWETH="78fd78b0";
const SEL_ZAPIN="c98c2c0b";
const SEL_PREVIEW_ZAP="e7cddab0";
const encPRouteWeth=(pools,tokenOut,amountIn,minOut,to)=>
"0x"+SEL_PROUTEWETH+encUint(160)+encAddr(tokenOut)+encUint(amountIn)
+encUint(minOut)+encAddr(to)+encUint(pools.length)+pools.map(encAddr).join("");
const encPRoute=(pools,tokenIn,tokenOut,amountIn,minOut,to)=>
"0x"+SEL_PROUTE+encUint(192)+encAddr(tokenIn)+encAddr(tokenOut)+encUint(amountIn)
+encUint(minOut)+encAddr(to)+encUint(BigInt(pools.length))+pools.map(encAddr).join("");
const SEL_PAIR_COUNT="355da246",SEL_CREATORBPS="17773ebb";
const PPOLICY="0x00000045fc7b570Be4d71F67219508ebD295EC6D";
const SEL_ROUTABLE="9662c498",SEL_QUOTE_ALL="89941805";
const LQ_SCAN=128;
const LQ_SHOW=24;
const isEthLike=a=>a===ZERO||a.toLowerCase()===WETH.toLowerCase();
async function quotePrecision(f,t,amountIn,sender,block){
if(PPLENS===ZERO||amountIn<=0n)return null;
const nat=a=>a.toLowerCase()===WETH.toLowerCase()?ZERO:a;
const vars=[];
const addVar=(a,b)=>{
const [x,y]=a.toLowerCase()<b.toLowerCase()?[a,b]:[b,a];
if(!vars.some(v=>v.c0===x&&v.c1===y&&v.tokenIn===a))vars.push({c0:x,c1:y,tokenIn:a});
};
const forms=a=>a===ZERO?[ZERO,WETH]
:a.toLowerCase()===WETH.toLowerCase()?[WETH,ZERO]:[a];
for(const a of forms(f.addr))for(const b of forms(t.addr)){
if(nat(a)===nat(b))continue;
addVar(a,b);
}
const reqs=[];
for(const v of vars)reqs.push(
{to:PPLENS,data:"0x"+SEL_QUOTE_BEST+encAddr(v.c0)+encAddr(v.c1)
+encAddr(sender)+encAddr(v.tokenIn)+encUint(amountIn)+encUint(0n)+encUint(BigInt(LQ_SCAN))},
{to:PFACTORY,data:"0x"+SEL_PAIR_COUNT+encAddr(v.c0)+encAddr(v.c1)});
const res=await mc3Deep(reqs,block);
let pool="",out=0n,n=0,fA=f.addr,won=null;
for(let i=0;i<vars.length;i++){
const q=res[i*2],c=res[i*2+1];
const b=decBest(q);
if(!b)continue;
if(b.out<=out)continue;
pool=b.pool;out=b.out;fA=vars[i].tokenIn;won=vars[i];
try{if(c)n=Number(BigInt(c))}catch{n=0}
}
if(!pool||!won)return await hubHop(f,t,amountIn,sender,block);
const tA=won.c0===fA?won.c1:won.c0;
let fee=0n;
const feeReq=p=>({to:PPLENS,
data:"0x"+SEL_EFFFEE+encAddr(p)+encAddr(sender)+encAddr(fA)+encUint(amountIn)});
const [fx,rt]=await mc3Deep([feeReq(pool),routableReq([pool])],block);
if(policyRefuses(rt,1)){
const alt=await bestRoutable(won.c0,won.c1,fA,amountIn,sender,block);
if(!alt)return await hubHop(f,t,amountIn,sender,block);
pool=alt.pool;out=alt.out;
const [fx2]=await mc3Deep([feeReq(pool)],block);
if(fx2)fee=BigInt(fx2);
}else if(fx)fee=BigInt(fx);
return {pools:[pool],out,fee,capped:n>LQ_SCAN,tokenIn:fA,tokenOut:tA,
unwrap:fA===ZERO&&f.addr!==ZERO?amountIn:0n,
wrap:fA!==ZERO&&f.addr===ZERO?amountIn:0n,
outDiffers:(tA===ZERO)!==(t.addr===ZERO)};
}
const routableReq=pools=>({to:PPOLICY,
data:"0x"+SEL_ROUTABLE+encUint(32)+encUint(BigInt(pools.length))+pools.map(encAddr).join("")});
function policyRefuses(raw,n){
if(!raw)return false;
const h=strip0x(raw);
if(h.length<128+n*64)return false;
const len=Number(BigInt("0x"+h.slice(64,128)));
if(len!==n)return false;
for(let i=0;i<n;i++)if(BigInt("0x"+h.slice(128+i*64,128+(i+1)*64))===0n)return true;
return false;
}
async function bestRoutable(c0,c1,tokenIn,amountIn,sender,block){
const [raw]=await mc3Deep([{to:PPLENS,data:"0x"+SEL_QUOTE_ALL+encAddr(c0)+encAddr(c1)
+encAddr(sender)+encAddr(tokenIn)+encUint(amountIn)+encUint(0n)+encUint(BigInt(LQ_SCAN))}],block);
const cands=decAll(raw);
if(!cands.length)return null;
const [rt]=await mc3Deep([routableReq(cands.map(c=>c.pool))],block);
if(!rt)return null;
const h=strip0x(rt);
if(h.length<128+cands.length*64)return null;
let win=null;
for(let i=0;i<cands.length;i++){
if(BigInt("0x"+h.slice(128+i*64,128+(i+1)*64))===0n)continue;
if(!win||cands[i].out>win.out)win=cands[i];
}
return win;
}
function decAll(raw){
if(!raw)return[];
const h=strip0x(raw);
if(h.length<128)return[];
const n=Number(BigInt("0x"+h.slice(64,128)));
const out=[];
for(let i=0;i<n;i++){
const b=128+i*192;
if(h.length<b+192)break;
const pool="0x"+h.slice(b+24,b+64),o=BigInt("0x"+h.slice(b+64,b+128));
if(o<=0n||/^0x0{40}$/i.test(pool))continue;
out.push({pool,out:o});
}
return out;
}
function decBest(raw){
if(!raw)return null;
const h=strip0x(raw);
if(h.length<128)return null;
const pool="0x"+h.slice(24,64),out=BigInt("0x"+h.slice(64,128));
if(out<=0n||/^0x0{40}$/i.test(pool))return null;
return {pool,out};
}
async function hubHop(f,t,amountIn,sender,block){
if(isEthLike(f.addr)||isEthLike(t.addr))return null;
const enc=(a,b,tokenIn,amt)=>{
const [c0,c1]=a.toLowerCase()<b.toLowerCase()?[a,b]:[b,a];
return [{to:PPLENS,data:"0x"+SEL_QUOTE_BEST+encAddr(c0)+encAddr(c1)
+encAddr(sender)+encAddr(tokenIn)+encUint(amt)+encUint(0n)+encUint(BigInt(LQ_SCAN))},
{to:PFACTORY,data:"0x"+SEL_PAIR_COUNT+encAddr(c0)+encAddr(c1)}]};
const count=raw=>{try{return raw?Number(BigInt(raw)):0}catch{return 0}};
const hubs=[ZERO,WETH];
const legs=[];
const first=await mc3Deep(hubs.flatMap(h=>enc(f.addr,h,f.addr,amountIn)),block);
for(let i=0;i<hubs.length;i++){
const b=decBest(first[i*2]);
if(b)legs.push({hub:hubs[i],pool:b.pool,mid:b.out,n:count(first[i*2+1])});
}
if(!legs.length)return null;
const second=await mc3Deep(legs.flatMap(l=>enc(l.hub,t.addr,l.hub,l.mid)),block);
let win=null;
for(let i=0;i<legs.length;i++){
const b=decBest(second[i*2]);
if(!b||(win&&b.out<=win.out))continue;
win={pools:[legs[i].pool,b.pool],out:b.out,mid:legs[i].mid,hub:legs[i].hub,
n:Math.max(legs[i].n,count(second[i*2+1]))};
}
if(!win)return null;
let fee=0n;
const [a,b,rt]=await mc3Deep([
{to:PPLENS,data:"0x"+SEL_EFFFEE+encAddr(win.pools[0])+encAddr(sender)+encAddr(f.addr)+encUint(amountIn)},
{to:PPLENS,data:"0x"+SEL_EFFFEE+encAddr(win.pools[1])+encAddr(sender)+encAddr(win.hub)+encUint(win.mid)},
routableReq(win.pools),
],block);
if(policyRefuses(rt,win.pools.length))return null;
const fa=a?BigInt(a):0n,fb=b?BigInt(b):0n;
fee=fa+fb-(fa*fb)/1000000n;
return {pools:win.pools,out:win.out,fee,capped:win.n>LQ_SCAN,
tokenIn:f.addr,tokenOut:t.addr,unwrap:0n,wrap:0n,outDiffers:false};
}
const QPAIR=2;
const SEL_BBS="e7798987";
const HUBS=()=>[WETH,...NUMERAIRES,"0x2260fac5e5542a773aa44fbcfedf7c193bc2c599","0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0"];
async function hubRoute(f,t,amt,sb,dl,to,rf,block){
const nf=(f.addr===ZERO?WETH:f.addr).toLowerCase(),nt=(t.addr===ZERO?WETH:t.addr).toLowerCase();
const H=HUBS().filter(h=>h.toLowerCase()!==nf&&h.toLowerCase()!==nt);
if(!H.length)return null;
const E=(x,i,o,n)=>({to:ZQUOTER,data:"0x"+SEL_BBS+encAddr(x)+encBool(false)+encAddr(i)+encAddr(o)+encUint(n)+encUint(sb)+encUint(dl)});
const D=h=>{try{return decQ(h,sb,false,0,4,0,6)}catch{return null}};
const L=[],r1=await mc3Deep(H.map(h=>E(ZROUTER,f.addr,h,amt)),block);
for(let i=0;i<H.length;i++){const a=r1[i]&&D(r1[i]);if(a&&a.amountLimit>0n)L.push({h:H[i],a})}
if(!L.length)return null;
const r2=await mc3Deep(L.map(x=>E(to,x.h,t.addr,x.a.amountLimit)),block);
let B=null;
for(let i=0;i<L.length;i++){const b=r2[i]&&D(r2[i]);
if(b&&b.best.amountOut>0n&&(!B||b.best.amountOut>B.b.best.amountOut))B={...L[i],b}}
if(!B)return null;
const c=[B.a.callData,B.b.callData,encSweep(B.h,0n,rf),encSweep(ZERO,0n,rf)];
return{best:{source:B.b.best.source,feeBps:B.b.best.feeBps,amountIn:amt,amountOut:B.b.best.amountOut},
callData:encCalls(c),amountLimit:B.b.amountLimit,
msgValue:f.addr===ZERO?amt:0n,spender:f.addr===ZERO?null:ZROUTER};
}
async function quoteV4Pools(f,t,amountIn,block){
const pools=v4PoolsFor(f,t);
if(!pools.length||amountIn<=0n)return null;
const rs=(await mc3Deep(pools.map(p=>({to:V4LENS,
data:"0x"+SEL_V4QUOTE+encBool(false)+encAddr(f.addr)+encAddr(t.addr)
+encUint(p.fee)+encUint(p.ts)+encAddr(p.hooks)+encUint(amountIn)})),block))
.map(h=>{try{const x=strip0x(h||"");return x.length>=128?BigInt("0x"+x.slice(64,128)):0n}catch{return 0n}});
let best=null;
for(let i=0;i<pools.length;i++)if(rs[i]>0n&&(!best||rs[i]>best.amountOut))
best={pool:pools[i],amountIn,amountOut:rs[i]};
return best;
}
const setListNote=t=>{
const el=document.getElementById("listNote");
if(!el)return;
el.textContent=t||"";
el.classList.toggle("hide",!t)};
const setListSource=w=>setListNote(w?"Built-in token list — "+w:"");
let rankFellBack=false;
const rankedIds=async()=>{
rankFellBack=false;
try{
const ids=decUintArr(await rpc(C,[{to:ZLISTLENS,data:"0x"+SEL_RANKEDIDS},L]));
if(ids.length)return ids;
}catch{}
try{
const ids=decUintArr(await rpc(C,[{to:TOKENLIST,data:"0x"+SEL_RANKEDIDS},L]));
if(ids.length)rankFellBack=true;
return ids;
}catch{return[]}
};
async function loadTokenList(){
if(TOKENLIST===ZERO)return setListSource("registry address not set");
try{
const ids=await rankedIds();
if(!ids.length)return setListSource("registry is empty");
const raw=await mc3Deep(ids.slice(0,64).map(id=>({to:TOKENLIST,data:"0x"+SEL_JSON+encUint(id)})));
const rows=raw.map(h=>{try{return h?decStr(h):null}catch{return null}});
const next=[];
for(const row of rows){
if(!row)continue;
let t;try{t=JSON.parse(row)}catch{continue}
if(t.k!=="eip155")continue;
const std=t.p==="Native"||t.p==="ERC-20"?"ft":t.p==="ERC-721"?"nft":"";
if(!std)continue;
if(!/^0x[0-9a-f]{40}$/i.test(t.a||""))continue;
if(!Number.isInteger(t.d)||t.d<0||t.d>36)continue;
if(next.some(x=>x.addr.toLowerCase()===t.a.toLowerCase()))continue;
const sym=safeSym(t.s).slice(0,12);
const logo=safeUrl(t.l);
next.push({sym,addr:t.a.toLowerCase(),dec:t.d,std,icon:logo?`<img src="${logo}" width="20" height="20">`:genIcon(sym),
name:String(t.n??"").slice(0,64),desc:String(t.desc??"").slice(0,240),
v4:parseV4Pools(t.e,t.a)});
}
next.sort((a,b)=>(a.std==="nft")-(b.std==="nft"));
if(!next.some(t=>t.std==="ft"))return setListSource("registry returned nothing swappable");
const mine=TOKENS.filter(t=>t.cust&&!next.some(x=>x.addr===t.addr.toLowerCase()));
let born=[];
LAUNCHED.length=0;
try{
const cnt=Number(BigInt(await rpc(C,[{to:PFACTORY,data:"0x"+SEL_BYCREATOR_N+encAddr(PLAUNCH)},L])||"0x0"));
const take=Math.min(cnt,LAUNCH_SCAN);
const raw=take?await rpc(C,[{to:PFACTORY,data:"0x"+SEL_BYCREATOR+encAddr(PLAUNCH)+encUint(BigInt(cnt-take))+encUint(BigInt(take))},L]):"0x";
const h=strip0x(raw||""),n=h.length>=128?Number(BigInt("0x"+h.slice(64,128)||"0")):0;
let pools=[];
for(let i=0;i<n&&i<take;i++)pools.push("0x"+h.slice(128+i*64+24,128+(i+1)*64));
if(pools.length){
const depth=await mc3Deep(pools.map(a=>[{to:a,data:"0x"+SEL_RESERVE0}]).flat());
const byDepth=pools.map((p,i)=>{let d=0n;try{d=BigInt(depth[i]||"0x0")}catch{}return{p,d}})
.sort((x,y)=>x.d===y.d?0:(x.d<y.d?1:-1)).slice(0,LAUNCH_SHOW);
pools=byDepth.map(x=>x.p);
const meta=await mc3Deep(pools.flatMap(a=>[{to:a,data:"0x"+SEL_TOKEN1}]));
const toks=[];
meta.forEach((x,i)=>{const a=x?("0x"+strip0x(x).slice(24)).toLowerCase():"";
if(/^0x[0-9a-f]{40}$/.test(a))toks.push({a,pi:i})});
const seen=new Set(next.map(x=>x.addr.toLowerCase()));
const info=await mc3Deep(toks.flatMap(({a})=>[{to:a,data:"0x95d89b41"},{to:a,data:"0x"+SEL_CONTRACTURI},
{to:PLAUNCH,data:"0x"+SEL_CREATOROF+encAddr(a)}]));
const taken=new Set(next.map(x=>x.sym.toLowerCase()));
toks.forEach(({a,pi},i)=>{
if(seen.has(a))return;
seen.add(a);
let sym="?";try{sym=safeSym(decodeString(info[i*3]||"0x").trim()).slice(0,12)}catch{}
if(!sym||sym==="?")return;
if(taken.has(sym.toLowerCase()))sym+=" "+a.slice(0,6)+"…";else taken.add(sym.toLowerCase());
let art="";try{art=imgFromContractURI(decodeString(info[i*3+1]||"0x"))}catch{}
if(art)logoCache[a]=art;
const dep=byDepth[pi]?byDepth[pi].d:0n;
let by="";try{const c="0x"+strip0x(info[i*3+2]||"").slice(24);if(/^0x[0-9a-f]{40}$/i.test(c)&&!/^0x0{40}$/i.test(c))by=short(c)}catch{}
const desc=[dep>0n?`${(+formatUnits(dep,18)).toFixed(dep<10n**16n?5:3)} ETH liquidity`:"no liquidity yet",
by?`by ${by}`:""].filter(Boolean).join(" \u00b7 ");
born.push({sym,addr:a,dec:18,std:"ft",name:"",desc,launched:1,dep,
icon:art?`<img width="20" height="20" style="border-radius:50%;object-fit:cover" src="${art}" alt="">`:genIcon(sym)});
LAUNCHED.push({addr:a,sym,pool:pools[pi]||""});
});
}
}catch{}
const anchors=BUILTIN.filter(b=>(b.addr===ZERO||b.addr===WETH)&&!next.some(x=>x.addr===b.addr));
const bornAt=new Set(born.map(x=>x.addr.toLowerCase()));
TOKENS.splice(0,TOKENS.length,...next,...anchors,...born,
...mine.filter(t=>!bornAt.has(t.addr.toLowerCase())));
setListNote(rankFellBack?"Ranked by listing order — conviction unavailable":"");
}catch(e){setListSource("could not be reached")}
}
const strip0x=h=>h.startsWith("0x")?h.slice(2):h;
const pad32=h=>strip0x(h).padStart(64,"0");
const encUint=v=>pad32(BigInt(v).toString(16));
const encAddr=a=>pad32((a||ZERO).toLowerCase());
const isAddr=a=>/^0x[0-9a-fA-F]{40}$/.test(a||"");
const decStr=hex=>{const h=strip0x(hex);const n=parseInt(h.slice(64,128),16);
return new TextDecoder().decode(hexToBytes(h.slice(128,128+n*2)))};
const decUintArr=hex=>{const h=strip0x(hex);const n=parseInt(h.slice(64,128),16);const o=[];
for(let i=0;i<n;i++)o.push(BigInt("0x"+h.slice(128+i*64,192+i*64)));return o};
const encBool=b=>pad32(b?"1":"0");
const toHex=v=>"0x"+BigInt(v).toString(16);
const parseUnits=(s,dec)=>{
const t=s.trim().replace(/,/g,"");
if(!/^(?:\d+|\d*\.\d+|\d+\.)$/.test(t))throw Error("invalid amount");
const[ip,fp=""]=t.split(".");
if(fp.length>dec)throw Error("too many decimals");
return BigInt((ip||"0")+fp.padEnd(dec,"0"));
};
const formatUnits=(v,dec)=>{
if(!dec)return BigInt(v).toString();
const s=BigInt(v).toString().padStart(dec+1,"0");
const ip=s.slice(0,-dec);
const fp=s.slice(-dec).replace(/0+$/,"");
return fp?`${ip}.${fp}`:ip;
};
const trimAmt=(v,dec)=>{const s=formatUnits(v,dec),i=s.indexOf(".");if(i<0)return s;const r=s.slice(0,i+7).replace(/\.?0+$/,"");return r==="0"&&v?s:r};
const maxAmt=(v,dec)=>{v=BigInt(v);if(dec<=6)return formatUnits(v,dec);
const u=10n**BigInt(dec-6);return formatUnits((v+u-1n)/u,6)};
const fitFont=el=>{
const l=el.value.length,s=l>18?".9em":l>14?"1.1em":l>10?"1.25em":"1.65em";
if(el.style.fontSize!==s)el.style.fontSize=s;
};
const decQ=(hex,slip,eo,u,v,S,mv)=>{
const h=strip0x(hex),num=i=>BigInt("0x"+h.slice(i*64,(i+1)*64)),E=()=>{throw Error("bad quote")};
if(h.length<(v+2)*64)E();
const o=Number(num(v))*2;if(o+64>h.length)E();
const n=Number(BigInt("0x"+h.slice(o,o+64)));if(!n||o+64+n*2>h.length)E();
const g=num(u+3),t=g>0n,k=S?(num(3)>0n?0:u):t?u:0,B=10000n,ai=S?num(2)+num(u+2):num(2),ao=S?num(3)+g:t?g:num(3),q=eo?ai:ao;
const src=[];for(let w=0;w<=u;w+=4)if(num(w+2)>0n||num(w+3)>0n)src.push(Number(num(w)));
return{best:{source:Number(num(k)),feeBps:num(k+1),amountIn:ai,amountOut:ao},sources:src,callData:"0x"+h.slice(o+64,o+64+n*2),amountLimit:eo?(q*(B+slip)+B-1n)/B:q*(B-slip)/B,msgValue:num(mv||v+1),slipBps:slip};
};
const merge=(est,exe)=>{if(!est)return exe;if(!exe)return null;return{...exe,best:est.best}};
const NO_WALLET="No wallet detected.";
let PROV=null;
const prov=()=>PROV||window.ethereum;
const rpc=(method,params)=>{const e=prov();
return e?e.request({method,params})
:Promise.reject(Object.assign(Error(NO_WALLET),{noWallet:true}))};
const rpcRead=async(method,params,tries=4)=>{
let last;
for(let i=0;i<tries;i++){
try{return await rpc(method,params)}
catch(e){last=e;await new Promise(r=>setTimeout(r,300*(i+1)))}
}
throw last;
};
const okRet=h=>{h=strip0x(h);if(h&&BigInt("0x"+h)===0n)throw Error("token returned false")};
const waitTx=async hash=>{
const end=Date.now()+600000;
let misses=0,wait=1500;
while(Date.now()<end){
try{
const r=await rpc("eth_getTransactionReceipt",[hash]);
misses=0;
if(r){
if(r.status!=="0x1")throw Error("tx reverted: "+hash);
return r;
}
wait=Math.min(wait+500,5000);
}catch(e){
if(/tx reverted/.test(e.message||""))throw e;
if(++misses>2)wait=Math.min(wait*2,15000);
}
await new Promise(res=>setTimeout(res,wait));
}
throw Error("tx not mined in time");
};
const checkWallet=async()=>{if(!account)throw Error("Connect a wallet first.");const[c,a]=await Promise.all([rpc(I,[]),rpc("eth_accounts",[])]);if(+c!==1||a[0]?.toLowerCase()!==account.toLowerCase())throw Error("wallet changed")};
const hexToBytes=h=>{const s=strip0x(h);const o=new Uint8Array(s.length/2);for(let i=0;i<o.length;i++)o[i]=parseInt(s.slice(i*2,i*2+2),16);return o};
const KRC=[1n,0x8082n,0x800000000000808an,0x8000000080008000n,0x808bn,0x80000001n,0x8000000080008081n,0x8000000000008009n,0x8an,0x88n,0x80008009n,0x8000000an,0x8000808bn,0x800000000000008bn,0x8000000000008089n,0x8000000000008003n,0x8000000000008002n,0x8000000000000080n,0x800an,0x800000008000000an,0x8000000080008081n,0x8000000000008080n,0x80000001n,0x8000000080008008n];
const KR=[0,1,62,28,27,36,44,6,55,20,3,10,43,25,39,41,45,15,21,8,18,2,61,56,14];
const KM=(1n<<64n)-1n;
const krol=(x,n)=>n?((x<<BigInt(n))|(x>>BigInt(64-n)))&KM:x;
const KCc=new Array(5),KB=new Array(25);
const keccak=b=>{const A=new Array(25).fill(0n),rate=136;
const pad=rate-(b.length%rate),buf=new Uint8Array(b.length+pad);buf.set(b);
buf[b.length]|=1;buf[buf.length-1]|=0x80;
for(let o=0;o<buf.length;o+=rate){
for(let i=0;i<17;i++){let v=0n;for(let j=7;j>=0;j--)v=(v<<8n)|BigInt(buf[o+i*8+j]);A[i]^=v}
for(let r=0;r<24;r++){
for(let x=0;x<5;x++)KCc[x]=A[x]^A[x+5]^A[x+10]^A[x+15]^A[x+20];
for(let x=0;x<5;x++){const D=KCc[(x+4)%5]^krol(KCc[(x+1)%5],1);for(let y=0;y<25;y+=5)A[x+y]^=D}
for(let x=0;x<5;x++)for(let y=0;y<5;y++)KB[y+5*((2*x+3*y)%5)]=krol(A[x+5*y],KR[x+5*y]);
for(let x=0;x<5;x++)for(let y=0;y<5;y++)A[x+5*y]=KB[x+5*y]^((~KB[(x+1)%5+5*y]&KM)&KB[(x+2)%5+5*y]);
A[0]^=KRC[r]}}
let out="";for(let i=0;i<4;i++){let v=A[i];for(let j=0;j<8;j++){out+=Number(v&0xffn).toString(16).padStart(2,"0");v>>=8n}}
return "0x"+out};
const namehash=n=>{let nd="0x"+"0".repeat(64);
if(n)for(const l of n.split(".").reverse())nd=keccak(new Uint8Array([...hexToBytes(nd),...hexToBytes(keccak(new TextEncoder().encode(l)))]));
return nd};
const encStr=v=>{const b=new TextEncoder().encode(v);let h="";
for(const x of b)h+=x.toString(16).padStart(2,"0");
return pad32("20")+encUint(b.length)+h.padEnd(Math.ceil(h.length/64)*64,"0")};
const retAddr=h=>{const s=strip0x(h||"");
if(s.length!==64||/[^0-9a-fA-F]/.test(s)||/[^0]/.test(s.slice(0,24)))return"";
const a="0x"+s.slice(24).toLowerCase();
return /^0x0{40}$/.test(a)?"":a};
const nameOk=n=>/^[\x21-\x7e]+$/.test(n)&&n.split(".").every(l=>l.length>0);
const nsFwd=async(reg,n)=>{const id=await rpc(C,[{to:reg,data:"0x"+SEL_CID+encStr(n)},L]);
if(strip0x(id||"").length!==64)return"";
return retAddr(await rpc(C,[{to:reg,data:"0x"+SEL_RES+strip0x(id)},L]))};
const dnsEnc=n=>{let h="";
for(const l of n.split(".")){const b=new TextEncoder().encode(l);
h+=b.length.toString(16).padStart(2,"0");
for(const x of b)h+=x.toString(16).padStart(2,"0")}
return h+"00"};
const encBytes=h=>{h=strip0x(h);return encUint(h.length/2)+h.padEnd(Math.ceil(h.length/64)*64,"0")};
const encResolve=(dns,inner)=>{const a=encBytes(dns);
return pad32("40")+encUint(64+a.length/2)+a+encBytes(inner)};
const decBytes=hex=>{const h=strip0x(hex||"");
if(h.length<128)return"";
const off=Number(BigInt("0x"+h.slice(0,64)))*2;
if(!Number.isSafeInteger(off)||off+64>h.length)return"";
const len=Number(BigInt("0x"+h.slice(off,off+64)))*2;
if(!Number.isSafeInteger(len)||off+64+len>h.length)return"";
return "0x"+h.slice(off+64,off+64+len)};
const ensFind=async n=>{const parts=n.split("."),
nodes=parts.map((_,i)=>namehash(parts.slice(i).join(".")));
const rs=await Promise.all(nodes.map(nd=>
rpc(C,[{to:ENSREG,data:"0x"+SEL_RSLV+pad32(nd)},L]).catch(()=>null)));
for(let i=0;i<nodes.length;i++){const r=retAddr(rs[i]);
if(r)return{r,nd:nodes[i],exact:i===0}}
return null};
const ensWild=async r=>{
try{const s=await rpc(C,[{to:r,data:supports(SEL_ERESOLVE)},L]);
return strip0x(s||"").length===64&&BigInt(s)===1n}catch{return false}};
const ensFwd=async n=>{const f=await ensFind(n);
if(!f)return"";
const inner="0x"+SEL_EADDR+pad32(f.nd);
if(f.exact)return retAddr(await rpc(C,[{to:f.r,data:inner},L]));
if(!await ensWild(f.r))return"";
try{return retAddr(decBytes(await rpc(C,[{to:f.r,
data:"0x"+SEL_ERESOLVE+encResolve(dnsEnc(n),inner)},L])))}
catch(e){
if(/556f1830/i.test((e&&e.data?JSON.stringify(e.data):"")+((e&&e.message)||"")))
throw Object.assign(Error(NAME_OFFCHAIN),{offchain:true});
return"";
}};
const ensRevName=async(nd,r)=>{
if(!r)return"";
try{return decodeString(await rpc(C,[{to:r,data:"0x"+SEL_ENAME+pad32(nd)},L])).trim()}catch{return""}};
const nameFwd=n=>/\.gwei$/i.test(n)?nsFwd(GNS,n):/\.wei$/i.test(n)?nsFwd(WNS,n):/\.eth$/i.test(n)?ensFwd(n):Promise.resolve("");
const FWD_TTL=30000;
const fwdCache=new Map();
const nameFwdCached=n=>{const hit=fwdCache.get(n);
if(hit&&hit.exp>Date.now())return hit.p;
const p=nameFwd(n);
fwdCache.set(n,{p,exp:Date.now()+FWD_TTL});
p.catch(()=>fwdCache.delete(n));
return p};
const nameRev=async a=>{
const nd=namehash(strip0x(a).toLowerCase()+".addr.reverse");
const [w,g,er]=await Promise.all([
{to:WNS,data:"0x"+SEL_REV+encAddr(a)},
{to:GNS,data:"0x"+SEL_REV+encAddr(a)},
{to:ENSREG,data:"0x"+SEL_RSLV+pad32(nd)}]
.map(c=>rpc(C,[c,L]).catch(()=>null)));
const str=h=>{try{return h?decodeString(h).trim():""}catch{return""}};
const agrees=async n=>{
if(!n||!nameOk(n.toLowerCase()))return"";
let f="";try{f=await nameFwdCached(n.toLowerCase())}catch{}
return f&&f.toLowerCase()===a.toLowerCase()?n:""};
return await agrees(str(w))||await agrees(str(g))
||await agrees(await ensRevName(nd,retAddr(er)))||""};
const decodeString=hex=>{
const h=strip0x(hex);
if(h.length<=64)return new TextDecoder().decode(hexToBytes(h)).replace(/\0+$/,"");
const off=Number(BigInt("0x"+h.slice(0,64)))*2;
const len=Number(BigInt("0x"+h.slice(off,off+64)))*2;
return new TextDecoder().decode(hexToBytes(h.slice(off+64,off+64+len)));
};
const kecStr=v=>keccak(new TextEncoder().encode(v));
const ckAddr=a=>{const s=strip0x(a);
if(s===s.toLowerCase()||s===s.toUpperCase())return true;
const h=strip0x(kecStr(s.toLowerCase()));
for(let i=0;i<40;i++){const c=s[i];
if(c>="a"&&c<="f"&&parseInt(h[i],16)>=8)return false;
if(c>="A"&&c<="F"&&parseInt(h[i],16)<8)return false}
return true};
const domainSep=(name,ver,tok)=>keccak(hexToBytes(
kecStr(EIP712DOM)+pad32(kecStr(name))+pad32(kecStr(ver))+encUint(CHAIN_ID)+encAddr(tok)));
const permitInfo=async(tok,owner)=>{
try{
const[ds,th,nc,nm]=await mc3Deep([
{to:tok,data:"0x"+SEL_DS},{to:tok,data:"0x"+SEL_PERMIT_TH},
{to:tok,data:"0x"+SEL_NONCES+encAddr(owner)},{to:tok,data:"0x"+SEL_NAME}]);
if(!ds||ds==="0x")return null;
if(th&&strip0x(th).length>=64&&strip0x(th).slice(0,64).toLowerCase()!==TH_2612)return null;
if(!nc||!nm)return null;
const nonce=BigInt(nc);
const name=decodeString(nm);
for(const ver of ["1","2"])if(domainSep(name,ver,tok).toLowerCase()===ds.toLowerCase())
return{name,ver,nonce};
}catc