0x68575b07…67c7·#25,914,161·view on Etherscan
LLET="No wallet detected.";
let PROV=null;
const prov=()=>PROV||window.ethereum;
const RPC_SEED=["https://ethereum-rpc.publicnode.com","https://eth-mainnet.public.blastapi.io"];
const RPC_STORE="zswap:rpc";
const rpcPin=()=>{try{const v=localStorage.getItem(RPC_STORE);
if(v&&/^https:\/\/\S+$/i.test(v))return v}catch{}return""};
let rpcPool=RPC_SEED.slice(),rpcPi=0,curated=0,curating=0,curatedTry=0;
const GAS_FLOOR=3000000000n;
const SEL_LIST="d77e4c79";
const decStrArr=h=>{const b=strip0x(h||"");if(b.length<128)return[];
const W=i=>parseInt(b.slice(i*64,i*64+64),16);
const off=W(0)/32;if(!Number.isInteger(off))return[];
const n=W(off);if(!(n>=0&&n<=64))return[];
const out=[];
for(let k=0;k<n;k++){
const rel=W(off+1+k)/32;if(!Number.isInteger(rel))return[];
const p=off+1+rel,len=W(p);if(!(len>=0&&len<=512))return[];
let str="";const base=(p+1)*64;
for(let j=0;j<len;j++)str+=String.fromCharCode(parseInt(b.slice(base+j*2,base+j*2+2),16));
out.push(str)}
return out};
const httpRead=async(u,method,params)=>{
const ac=new AbortController(),kill=setTimeout(()=>ac.abort(),15000);
try{
let r;
try{r=await fetch(u,{method:"POST",headers:{"content-type":"application/json"},
body:JSON.stringify({id:1,jsonrpc:"2.0",method,params:params||[]}),signal:ac.signal})}
catch{throw Object.assign(Error("could not reach the read node"),{retry:1})}
if(!r.ok)throw Object.assign(Error("a read node answered "+r.status),{retry:1});
let j;try{j=await r.json()}catch{throw Object.assign(Error("a read node sent an unreadable answer"),{retry:1})}
if(j&&j.error){const c=j.error.code;
throw Object.assign(Error(j.error.message||"the read node refused"),{code:c,data:j.error.data,
retry:c==null||c===-32005||c===-32603||c===-32004||c===-32002||c===-32001||c===429})}
return j?j.result:null;
}finally{clearTimeout(kill)}};
const loadCurated=async()=>{
if(curating||Date.now()-curatedTry<60000)return;
curating=1;curatedTry=Date.now();
try{
const a=RPCS_PIN;
const alt=RPC_SEED.find(u=>u!==rpcPool[rpcPi])||RPC_SEED[0];
const [a1,a2]=await Promise.all([
httpRead(rpcPool[rpcPi],"eth_call",[{to:a,data:"0x"+SEL_LIST},L]),
httpRead(alt,"eth_call",[{to:a,data:"0x"+SEL_LIST},L])]);
if(!a1||!a2||strip0x(a1)!==strip0x(a2))return;
const urls=decStrArr(a1).map(s=>s.trim()).filter(s=>/^https:\/\/\S+$/.test(s));
if(!urls.length)return;
rpcPool=[...new Set(urls.concat(rpcPool,RPC_SEED))];
curated=1;
}catch{}
finally{curating=0}};
const OX_ETH="0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
const OKX_APPROVE={1:"0x40aA958dd87FC8305b97f2BA922CDdCa374bcD7f",8453:"0x57df6092665eb6058DE53939612413ff4B09114E"};
const bmin=(a,b)=>a<b?a:b,bmax=(a,b)=>a>b?a:b;
const SEL_SLIST="e3b06401",SEL_EXEC="495c73b0",SEL_FILL="0a1b4c9f";
const SOLVERS_PIN="0x1Dfbb2f41B596F72187370469074C46de60dA2e3";
const RPCS_PIN="0x8C7348D039f58C4e9cfA936EF410eec759213b12";
let SOLVER_FILL_PIN="0x7A2f21e476cA2ADde027BC868c5a083338EEfE54";
const SOLVER_ROW_TAG="0x7A2f21e476cA2ADde027BC868c5a083338EEfE54";
let SOLVER_EXEC_PIN="0x4f6633342045C80Efa6c8CAc41b9bdc6145168C4";
const SRC_SOLVER=9;
const SRC_DEEP=10;
const SOLVER_DEADLINE=1500,SOLVER_STRIKES=3,SOLVER_COOL=60000;
let solverLanes=null,solverFill=null,solverExec=null,solversJob=null;
const _strikes=new Map();
const laneHurt=n=>{const s=_strikes.get(n),t=Date.now();_strikes.set(n,{n:(s&&t-s.t<SOLVER_COOL?s.n:0)+1,t})};
const laneDown=n=>{const s=_strikes.get(n);return!!s&&Date.now()-s.t<SOLVER_COOL&&s.n>=SOLVER_STRIKES};
const laneSaw=(n,st)=>{if(st===401||st===403||st===429)laneHurt(n)};
const laneThrew=(n,e)=>{if(!e||e.name!=="AbortError")laneHurt(n)};
const laneOk=c=>!!c&&isAddr(c.target)&&(c.spender==null||isAddr(c.spender))
&&/^0x[0-9a-fA-F]*$/.test(c.data||"")&&strip0x(c.data||"").length%2===0;
const decSolvers=h=>{const b=strip0x(h||"");if(b.length<128)return[];
const W=i=>parseInt(b.slice(i*64,i*64+64),16);
const str=w=>{const n=W(w);if(!(n>=0&&n<=256))return null;let o="";const base=(w+1)*64;
for(let j=0;j<n;j++)o+=String.fromCharCode(parseInt(b.slice(base+j*2,base+j*2+2),16));return o};
try{
const head=W(0)/32;if(!Number.isInteger(head))return[];
const n=W(head);if(!(n>=0&&n<=64))return[];
const out=[];
for(let k=0;k<n;k++){
const rel=W(head+1+k)/32;if(!Number.isInteger(rel))return[];
const t=head+1+rel;
const nameOff=W(t)/32,epOff=W(t+1)/32;
if(!Number.isInteger(nameOff)||!Number.isInteger(epOff))return[];
const name=str(t+nameOff),endpoint=str(t+epOff);
if(name===null||endpoint===null)return[];
const hash=endpoint.indexOf("#");
const flag=hash<0?"":endpoint.slice(hash+1);
const url=hash<0?endpoint:endpoint.slice(0,hash);
const m=/(?:^|;)c=([0-9,]+)/.exec(flag);
const chains=m?m[1].split(",").map(Number).filter(Boolean):[1];
out.push({name,endpoint:url,chains,
adapter:"0x"+b.slice((t+2)*64+24,(t+3)*64),
handicapBps:BigInt(W(t+3)),
enabled:W(t+4)===1});
}
return out}catch{return[]}};
const loadSolvers=()=>solversJob||(solversJob=(async()=>{
try{
const list=SOLVERS_PIN;
solverFill=SOLVER_FILL_PIN;
const ex=await nodeRead("eth_call",[{to:solverFill,data:"0x"+SEL_EXEC},L]).catch(()=>null);
const exec="0x"+strip0x(ex||"0x").slice(24);
if(!isAddr(exec)){solversJob=null;return}
if(exec.toLowerCase()!==SOLVER_EXEC_PIN.toLowerCase()){solverLanes=[];return}
solverExec=SOLVER_EXEC_PIN;
const raw=await cfgRead("eth_call",[{to:list,data:"0x"+SEL_SLIST},L]);
solverLanes=decSolvers(raw).filter(x=>x.enabled
&&x.adapter.toLowerCase()===SOLVER_ROW_TAG.toLowerCase()
&&/^https:\/\/\S+$/.test(x.endpoint)
&&SOLVER_SHAPES[x.name]
&&x.chains.includes(CHAIN_ID)
&&chainCfg().slvId);
}catch{solversJob=null}
})());
const lanePost=async(name,url,body,ms)=>{
const ac=new AbortController(),k=setTimeout(()=>ac.abort(),ms);
try{const r=await fetch(url,{method:"POST",headers:{"content-type":"application/json"},
body:JSON.stringify(body),signal:ac.signal});laneSaw(name,r.status);
if(!r.ok)return null;return await r.json()}
catch(e){laneThrew(name,e);return null}finally{clearTimeout(k)}};
const LANE_TTL=15000,LANE_MAX=64;
const _laneHit=new Map(),_laneWait=new Map();
const laneCached=(k,go)=>{
const c=_laneHit.get(k);
if(c&&Date.now()-c.t<LANE_TTL){_laneHit.delete(k);_laneHit.set(k,c);return Promise.resolve(c.v)}
const w=_laneWait.get(k);
if(w)return w;
const pr=go().then(v=>{
_laneWait.delete(k);
if(v!==null&&v!==undefined){_laneHit.set(k,{v,t:Date.now()});
if(_laneHit.size>LANE_MAX)_laneHit.delete(_laneHit.keys().next().value);}
return v},e=>{_laneWait.delete(k);throw e});
_laneWait.set(k,pr);return pr};
let laneOverride=null,laneOverrideFor="";
const laneScope=()=>`${fromSel.value}|${toSel.value}|${tab}|${mode}`;
const lanePin=()=>laneOverride&&laneOverrideFor===laneScope()?laneOverride:null;
const laneGet=async(name,url,ms)=>{
const ac=new AbortController(),k=setTimeout(()=>ac.abort(),ms);
try{const r=await fetch(url,{signal:ac.signal});laneSaw(name,r.status);
if(!r.ok)return null;return await r.json()}
catch(e){laneThrew(name,e);return null}finally{clearTimeout(k)}};
const SOLVER_SHAPES_OUT={
"0x":async(ep,f,t,amt,slip,ms)=>{
const q=new URLSearchParams({chainId:chainCfg().slvId,sellToken:f===ZERO?OX_ETH:f,buyToken:t===ZERO?OX_ETH:t,
buyAmount:amt.toString(),taker:solverExec,slippageBps:String(slip)});
const j=await laneGet("0x",`${ep}/swap/allowance-holder/quote?${q}`,ms);
if(!j||!j.transaction||!j.estimatedNetSellAmount)return null;
return{inp:BigInt(j.estimatedNetSellAmount),
cap:j.maxSellAmount?BigInt(j.maxSellAmount):0n,
target:j.transaction.to,spender:j.allowanceTarget||j.transaction.to,data:j.transaction.data}},
"ParaSwap":async(ep,f,t,amt,slip,ms,fd,td)=>{
const q=new URLSearchParams({srcToken:f===ZERO?OX_ETH:f,destToken:t===ZERO?OX_ETH:t,
amount:amt.toString(),srcDecimals:String(fd??18),destDecimals:String(td??18),
side:"BUY",network:chainCfg().slvId,version:"6.2"});
const pr=await laneGet("ParaSwap",`${ep}/prices?${q}`,ms);
const route=pr&&pr.priceRoute;if(!route||!route.srcAmount)return null;
const j=await lanePost("ParaSwap",`${ep}/transactions/${chainCfg().slvId}?ignoreChecks=true`,{
srcToken:f===ZERO?OX_ETH:f,destToken:t===ZERO?OX_ETH:t,
srcDecimals:route.srcDecimals,destDecimals:route.destDecimals,
priceRoute:route,userAddress:solverExec,slippage:Number(slip)},ms);
if(!j||!j.to||!j.data)return null;
return{inp:bmax(BigInt(route.srcAmount),BigInt(route.srcAmountAfterFee||route.srcAmount)),
target:j.to,spender:route.tokenTransferProxy||j.to,data:j.data}},
};
const SOLVER_SHAPES={
"0x":async(ep,f,t,amt,slip,ms)=>{
const q=new URLSearchParams({chainId:chainCfg().slvId,sellToken:f===ZERO?OX_ETH:f,buyToken:t===ZERO?OX_ETH:t,
sellAmount:amt.toString(),taker:solverExec,slippageBps:String(slip)});
const j=await laneGet("0x",`${ep}/swap/allowance-holder/quote?${q}`,ms);
if(!j||!j.transaction||!j.buyAmount)return null;
return{out:BigInt(j.buyAmount),target:j.transaction.to,
spender:j.allowanceTarget||j.transaction.to,data:j.transaction.data}},
"ParaSwap":async(ep,f,t,amt,slip,ms,fd,td)=>{
const q=new URLSearchParams({srcToken:f===ZERO?OX_ETH:f,destToken:t===ZERO?OX_ETH:t,
amount:amt.toString(),srcDecimals:String(fd??18),destDecimals:String(td??18),
side:"SELL",network:chainCfg().slvId,version:"6.2"});
const pr=await laneGet("ParaSwap",`${ep}/prices?${q}`,ms);
const route=pr&&pr.priceRoute;if(!route||!route.destAmount)return null;
const j=await lanePost("ParaSwap",`${ep}/transactions/${chainCfg().slvId}?ignoreChecks=true`,{
srcToken:f===ZERO?OX_ETH:f,destToken:t===ZERO?OX_ETH:t,
srcDecimals:route.srcDecimals,destDecimals:route.destDecimals,
priceRoute:route,userAddress:solverExec,slippage:Number(slip)},ms);
if(!j||!j.to||!j.data)return null;
return{out:bmin(BigInt(route.destAmount),BigInt(route.destAmountAfterFee||route.destAmount)),
target:j.to,spender:route.tokenTransferProxy||j.to,data:j.data}},
"KyberSwap":async(ep,f,t,amt,slip,ms)=>{
const q=new URLSearchParams({tokenIn:f===ZERO?OX_ETH:f,tokenOut:t===ZERO?OX_ETH:t,amountIn:amt.toString()});
const pr=await laneGet("KyberSwap",`${ep}/${chainCfg().slvSlug}/api/v1/routes?${q}`,ms);
const rs=pr&&pr.data&&pr.data.routeSummary;if(!rs||!rs.amountOut)return null;
const j=await lanePost("KyberSwap",`${ep}/${chainCfg().slvSlug}/api/v1/route/build`,
{routeSummary:rs,sender:solverExec,recipient:solverExec,slippageTolerance:Number(slip)},ms);
const d=j&&j.data;if(!d||!d.data||!d.routerAddress)return null;
return{out:BigInt(rs.amountOut),target:d.routerAddress,spender:d.routerAddress,data:d.data}},
"Enso":async(ep,f,t,amt,slip,ms)=>{
const q=new URLSearchParams({chainId:chainCfg().slvId,fromAddress:solverExec,receiver:solverExec,
tokenIn:f===ZERO?OX_ETH:f,tokenOut:t===ZERO?OX_ETH:t,amountIn:amt.toString(),
slippage:String(slip),routingStrategy:"router"});
const j=await laneGet("Enso",`${ep}?${q}`,ms);
if(!j||!j.amountOut||!j.tx||!j.tx.to)return null;
return{out:BigInt(j.amountOut),target:j.tx.to,spender:j.tx.to,data:j.tx.data}},
"OKX":async(ep,f,t,amt,slip,ms)=>{
const q=new URLSearchParams({chainIndex:chainCfg().slvId,fromTokenAddress:f===ZERO?OX_ETH:f,
toTokenAddress:t===ZERO?OX_ETH:t,amount:amt.toString(),
slippagePercent:(Number(slip)/100).toString(),userWalletAddress:solverExec,swapMode:"exactIn"});
const j=await laneGet("OKX",`${ep}/dex/aggregator/swap?${q}`,ms);
const d=j&&j.code==="0"&&j.data&&j.data[0];
if(!d||!d.tx||!d.tx.to||!d.routerResult||!d.routerResult.toTokenAmount)return null;
let sp=f===ZERO?d.tx.to:OKX_APPROVE[CHAIN_ID];
if(!sp){const a=await laneGet("OKX",`${ep}/dex/aggregator/approve-transaction?${new URLSearchParams({chainIndex:chainCfg().slvId,tokenContractAddress:f,approveAmount:amt.toString()})}`,ms);
const x=a&&a.code==="0"&&a.data&&a.data[0]&&a.data[0].dexContractAddress;if(isAddr(x))sp=OKX_APPROVE[CHAIN_ID]=x}
if(!sp)return null;
return{out:BigInt(d.routerResult.toTokenAmount),target:d.tx.to,spender:sp,data:d.tx.data}},
"Bebop":async(ep,f,t,amt,slip,ms)=>{
if(f===ZERO||t===ZERO)return null;
const q=new URLSearchParams({sell_tokens:f,buy_tokens:t,sell_amounts:amt.toString(),
taker_address:solverExec,gasless:"false",approval_type:"Standard"});
const j=await laneGet("Bebop",`${ep}/quote?${q}`,ms);
const rs=j&&j.routes;if(!rs||!rs.length)return null;
const route=rs.find(x=>x.type===j.bestPrice)||rs[0];
const qq=route&&route.quote;if(!qq||!qq.tx||!qq.buyTokens)return null;
const info=Object.values(qq.buyTokens)[0];
if(!info||!info.amount||!qq.tx.to)return null;
const bebSp=qq.approvalTarget||qq.approval_target;
if(!isAddr(bebSp||""))return null;
return{out:BigInt(info.amount),target:qq.tx.to,spender:bebSp,data:qq.tx.data}},
"1inch":async(ep,f,t,amt,slip,ms)=>{
const q=new URLSearchParams({src:f===ZERO?OX_ETH:f,dst:t===ZERO?OX_ETH:t,amount:amt.toString(),
from:solverExec,origin:solverExec,slippage:String(Number(slip)/100),disableEstimate:"true"});
const j=await laneGet("1inch",`${ep}/swap/v6.0/${chainCfg().slvId}/swap?${q}`,ms);
if(!j||!j.tx||!j.dstAmount)return null;
return{out:BigInt(j.dstAmount),target:j.tx.to,spender:j.tx.to,data:j.tx.data}},
};
const RPC_TRIES=4;
const nodeRead=async(method,params)=>{
let last;
const pin=CHAIN_ID===1?rpcPin():"";
const tries=Math.min(rpcPool.length,RPC_TRIES);
const p=rpcPi;
for(let i=pin?-1:0;i<tries;i++){
const j=(p+i)%rpcPool.length;
const u=i<0?pin:rpcPool[j];
try{const r=await httpRead(u,method,params);if(i>=0)rpcPi=j;
if(!curated)loadCurated().catch(()=>{});
return r}
catch(e){last=e;if(!e.retry)throw e}}
throw last||Error("no read node answered")};
const isSign=m=>m===S||m.indexOf("wallet_")===0||m==="eth_requestAccounts"||m==="eth_accounts"||WC_SIGN.indexOf(m)>=0;
const hexOk=r=>typeof r==="string"&&!/^0x[0-9a-fA-F]*$/.test(r)?Promise.reject(Error("bad hex from node")):r;
const rpc=(method,params)=>{const e=prov();
const p=e?e.request({method,params})
:isSign(method)?Promise.reject(Object.assign(Error(NO_WALLET),{noWallet:true})):nodeRead(method,params);
return method===C?p.then(hexOk):p};
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;if(i+1<tries)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!==CHAIN_ID)throw Error("Switch your wallet to "+chainCfg().name);if(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 strTail=v=>{const b=new TextEncoder().encode(v);let h="";
for(const x of b)h+=x.toString(16).padStart(2,"0");
return encUint(b.length)+h.padEnd(Math.ceil(h.length/64)*64,"0")};
const encStr=v=>pad32("20")+strTail(v);
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=>/^[a-z0-9.-]+$/.test(n)
&&n.split(".").every(l=>l.length>0&&l.length<64&&l[0]!=="-"&&l[l.length-1]!=="-");
const nsFwd=async(reg,n)=>{const id=await cfgRead(C,[{to:reg,data:"0x"+SEL_CID+encStr(n)},L]);
if(strip0x(id||"").length!==64)return"";
return retAddr(await cfgRead(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=>
cfgRead(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 cfgRead(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 cfgRead(C,[{to:f.r,data:inner},L]));
if(!await ensWild(f.r))return"";
try{return retAddr(decBytes(await cfgRead(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 cfgRead(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=>cfgRead(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","1.0","V1",""])if(domainSep(name,ver,tok).toLowerCase()===ds.toLowerCase())
return{name,ver,nonce};
}catch{}
return null};
const signPermit=async(tok,info,owner,value,deadline)=>{
const td={types:{EIP712Domain:[{name:"name",type:"string"},{name:"version",type:"string"},
{name:"chainId",type:"uint256"},{name:"verifyingContract",type:"address"}],
Permit:[{name:"owner",type:"address"},{name:"spender",type:"address"},
{name:"value",type:"uint256"},{name:"nonce",type:"uint256"},{name:"deadline",type:"uint256"}]},
primaryType:"Permit",domain:{name:info.name,version:info.ver,chainId:CHAIN_ID,verifyingContract:tok},
message:{owner,spender:ZROUTER,value:value.toString(),nonce:info.nonce.toString(),deadline:deadline.toString()}};
const sig=strip0x(await rpc("eth_signTypedData_v4",[owner,JSON.stringify(td)]));
if(sig.length!==130)throw Error("bad signature");
let v=parseInt(sig.slice(128,130),16);if(v<27)v+=27;
return"0x"+SEL_RPERMIT+encAddr(tok)+encUint(value)+encUint(deadline)+encUint(v)+sig.slice(0,64)+sig.slice(64,128)};
const P2DOM=()=>({name:"Permit2",chainId:CHAIN_ID,verifyingContract:PERMIT2});
const p2Ready=async(tok,owner)=>{
try{return BigInt(await rpc(C,[{to:tok,data:"0x"+SEL_ALLOWANCE+encAddr(owner)+encAddr(PERMIT2)},L]))}catch{return 0n}};
const signPermit2=async(tok,owner,amount,deadline)=>{
const nonce=BigInt("0x"+[...crypto.getRandomValues(new Uint8Array(31))].map(b=>b.toString(16).padStart(2,"0")).join(""));
const td={types:{EIP712Domain:[{name:"name",type:"string"