memoscan
← all memos

Memo 0xb0f72479…6d9f19 on Ethereum

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"