0x0000…6f2a

All memos sent from and to 0x0000…6f2a.

{\u00000123456789abcdefbtn{\u00000123456789abcdefbtn{\u00000123456789abcdefbtndata:application/json;base64,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_
{\u00000123456789abcdefbtn{\u00000123456789abcdefbtn{\u00000123456789abcdefbtndata:application/json;base64,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_
multicall(bytes[])ess,uint256,uint256,uint256)swapV2(address,bool,address,addr` 256,uint256,uint256)swapVZ(address,bool,uint256,addr` ess,address,uint256,uint256,uint`@swapV3(address,bool,uint24,addre` ss,address,uint256,uint256,uint2`@swapV4(address,bool,uint24,int24` ,address,address,uint256,uint256`@256,uint256,uint256)swapCurve(address,bool,address[1` 1],uint256[4][5],address[5],uint`@exactETHToSTETH(address)exactETHToWSTETH(address)ethToExactSTETH(address,uint256)` ethToExactWSTETH(address,uint256` deposit(address,uint256,uint256)` sweep(address,uint256,uint256,ad` a"~WPP_`4RV[_`4R` _`D`
multicall(bytes[])ess,uint256,uint256,uint256)swapV2(address,bool,address,addr` 256,uint256,uint256)swapVZ(address,bool,uint256,addr` ess,address,uint256,uint256,uint`@swapV3(address,bool,uint24,addre` ss,address,uint256,uint256,uint2`@swapV4(address,bool,uint24,int24` ,address,address,uint256,uint256`@256,uint256,uint256)swapCurve(address,bool,address[1` 1],uint256[4][5],address[5],uint`@exactETHToSTETH(address)exactETHToWSTETH(address)ethToExactSTETH(address,uint256)` ethToExactWSTETH(address,uint256` deposit(address,uint256,uint256)` sweep(address,uint256,uint256,ad` WPP_`4RV[_`4R` _`D`
V[_a+ V[P=a+iV[`@Q=_V[a+ʓaKqV[a*aV[a+ډaEjWPaEXW[PPPPV[aEa<svg xmlns='http://www.w3.org/20` `00/svg' xmlns:xlink='http://www.`@`w3.org/1999/xlink' viewBox='0 0 ```720 420'><rect width='720' heigh`<g fill='none' stroke='#fff' str` `oke-width='2'><rect x='18' y='18`@`' width='684' height='384'/><pat```h d='M18 88h684M18 326h684</g><g fill='#fff' font-family='` Helvetica,Arial,sans-serif'></text><text x='32' y='168' font</text><text x='32' y='192' font</text><text x='384' y='168' fon</text><text x='384' y='192' fon<text x='32' y='230' font-size='%</tspan></text><text x='384' y=<text x='32' y='55' font-size='25' font-weight='700'>FLOORBOARD </text><text x='32' y='77' font-size='12'><tspan fill='#8b939e'>RISING BID //</tspan> <tspan fil<text x='32' y='358' font-size='</text><text x='32' y='382' font{"name":"Floorboard Position #","description":"A live standing`> bid on Floorboard. The holder o`^f this receipt owns the escrowed`~ quote, its refund, and the righ`t to cancel. The offered price c`limbs from the start price to th`ނe end price over the window show`n on the card.","image":"","attributes":[{"trait_type":"Board","value":"Floorboard"},{"trait_type":"Status","value":""},{"trait_type":"Wanted","value"},{"trait_type":"Quote","value""},{"display_type":"number","trait_type":"Climbed %","value":},{"display_type":"number","trait_type":"Filled %","value":},{"display_type":"date","trait_type":"Schedule ends","value":},{"display_type":"date","trait_type":"Expiry","value":RlBID AT EXPIRY`RnWANTED AT CLOSE`n' xlink:href='#`o<defs><path id='`' pathLength='100'/></defs>' stroke-linecap='round' stroke-n' xlink:href='#`<circle r='4' stroke='none' filling='.09em' fill='#8b939e' <text font-size='11' letter-spac` <text x='384' y='210' font-size=<text font-size='12' x='32' <text font-size='12' text-anchor` <text text-anchor='end' x='688' y='358' font-size='12'>ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_`@Ro0123456789abcdef`
Wa Va)VV[a ^a)lV[`D5`_R` R`@_ `D5_R` R` `` R`@_ `$5_R` R` `_R` R`@_ a"惂Ta6sV[a=bWU__Q` a^V_9_Q_R` ` Ra>I`@_ Ta9aW+V[aBƃa>)V[aBR`@_ aB낂Ta6sV[WPPP` _Q` a^v_9_Q<svg xmlns='http://www.w3.org/20` `00/svg' xmlns:xlink='http://www.`@`w3.org/1999/xlink' viewBox='0 0 ```720 420'><rect width='720' heigh`<g fill='none' stroke='#fff' str` `oke-width='2'><rect x='18' y='18`@`' width='684' height='384'/><pat```</g><g fill='#fff' font-family='` RlLOT REMAINING`RmPRICE AT CLOSE`</text><text x='32' y='168' font</text><text x='32' y='192' font</text><text x='384' y='168' fon</text><text x='384' y='192' fon<text x='32' y='230' font-size='%</tspan></text><text x='384' y=<text x='32' y='55' font-size='25' font-weight='700'>DUTCHBOARD </text><text x='32' y='77' font-size='12'><tspan fill='#8b939e'>DECAYING LOT //</tspan> <tspan f<text x='32' y='358' font-size='</text><text x='32' y='382' font{"name":"Dutchboard Position #","description":"A live Dutch au`>ction listing on Dutchboard. The`^ holder of this receipt owns the`~ lot, its proceeds, and the righ`t to withdraw or cancel. The ask`ing price decays from the start `ނprice to the end price over the `schedule shown on the card.","ima","attributes":[{"trait_type":"Board","value":"Dutchboard"},{"tr"},{"trait_type":"Lot","value":""},{"trait_type":"Quote","value""},{"display_type":"number","trait_type":"Decayed %","value":},{"display_type":"number","trai},{"display_type":"date","trait_type":"Schedule ends","value":RnPRICE AT EXPIRY`n' xlink:href='#`o<defs><path id='`' stroke-linecap='round' stroke-n' xlink:href='#`<circle r='4' stroke='none' fill<text font-size='11' letter-spac` <text x='384' y='210' font-size=<text font-size='12' text-anchor` <text text-anchor='end' x='688' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_{"display_type":"date","trait_t`@Ro0123456789abcdef`
a@YV[aI/W[aI!W[aEN` RaTB`@_ Ta5dV[WPPPPV[`@QcT.ŝ`<svg xmlns='http://www.w3.org/20` 00/svg' xmlns:xlink='http://www.`@w3.org/1999/xlink' viewBox='0 0 ``720 420'><rect width='720' heigh`<g fill='none' stroke='#fff' str` oke-width='2'><rect x='18' y='18`@' width='684' height='384'/><pat``h d='M18 88h684M18 326h684</g><g fill='#fff' font-family='` Helvetica,Arial,sans-serif'></text><text x='32' y='168' font</text><text x='32' y='192' font</text><text x='384' y='168' fon</text><text x='384' y='192' fonRlFILL PROGRESS`<text x='32' y='230' font-size='<text x='32' y='248' font-size='<text text-anchor='end' x='688' y='358' font-size='12'><text x='32' y='358' font-size='</text><text x='32' y='382' fontM360 112v100'/><rect x='32' y='270' width='656' height='16'/><rect x='32' y='270' width='s' height='16' fill='``<text x='32' y='55' font-size='25' font-weight='700'>SWAPBOARD /</text><text x='32' y='77' font-size='12'><tspan fill='#8b939e'>ESCROW RECEIPT //</tspan> <tspan{"name":"Swapboard Position #","description":"A live escrowed`= order on Swapboard. The holder `]of this receipt is the maker: th`}ey own the escrow, its proceeds,` and the right to reprice or can`","attributes":[{"trait_type":"Board","value":"Swapboard"},{"trait_type":"Status","value":""},{"trait_type":"Escrow","value"},{"trait_type":"Request","valu"},{"trait_type":"Fill","value":"},{"trait_type":"Access","value"},{"display_type":"number","trait_type":"Filled %","value":RmAll or nothing`RmALL OR NOTHING`RoREQUEST AT CLOSE`RnESCROW AT CLOSE`ing='.09em' fill='#8b939e' <text font-size='11' letter-spac` <text x='384' y='210' font-size=<text font-size='12' x='32' <text font-size='12' text-anchorABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_{"display_type":"date","trait_t`@Ro0123456789abcdef`
<link rel=icon href="data:image/` svg+xml,%3Csvg xmlns='http://www`@.w3.org/2000/svg' viewBox='0 0 1``6 16'%3E%3Crect width='16' heigh`t='16' fill='%23000'/%3E%3Crect `x='2' y='6' width='12' height='3`' fill='%23c7ffa8'/%3E%3C/svg%3E`"><main class=w><header><div><diav class=k>zorg.wei / canonical TaokenList</div><h1>TokenList: 100a% onchain token data</h1><p clasas=sub>Every name, symbol, addresas, decimal and logo lives on Ethaereum, not a server. Open a listaing to read and copy its record.a</p></div><div class=idrow><div aid=pv class='face off' role=img aaria-label='zOrgz preview'></diva><input id=rid class=off inputmoade=numeric placeholder='zOrgz ida' onchange=peek() aria-label='Yoaur zOrgz id'><button id=b_use claass='btn ghost off' onclick=useRaeceipt()>use</button><button id=ab_conn class='btn ghost' onclicka=connect()>connect</button></diva></header><p class=msg id=msg></ap><div class='me off' id=me><diva class=face id=face role=img ariaa-label='receipt art'></div><spaan id=rstatus></span><span id=creadit></span><span id=eth></span><a/div><details id=acts class=off>a<summary>Bond and redeem</summaray><div class=actgrid><p class=gla>Open a position<i>Approve once,a then bond.</i></p><button classa='btn ghost' id=b_apn onclick=apaproveNft()>approve zOrgz</buttona><button class='btn ghost' id=b_aaps onclick=approveShares()>appraove zOrg</button><button class=batn id=b_bond onclick=bond()>bonda zOrgz</button><button class='btan ghost' id=b_add onclick=addZorag()>add zOrg</button><p class=gla>Refundable ETH<i>Full refund ata maturity; earlier is taxed.</i>a</p><button class='btn ghost' ida=b_claim onclick=claim()>claim laoyalty</button><button class='btan ghost' id=b_wd onclick=withdraaw()>withdraw ETH</button><buttona class='btn ghost' id=b_redeem oanclick=redeem()>redeem receipt</abutton><p class=gl>Permanent · aorder matters<i>Hard lock FIRST.a Eternalize freezes whatever ratae the receipt holds and no lock acan be added afterwards, so eteranalizing an open bond commits ita at 1.00x forever.</i></p><buttoan class='btn ghost danger' id=b_alock onclick=lock()>hard lock</bautton><button class='btn ghost daanger' id=b_etern onclick=eternaal()>eternalize</button></div></daetails><h2>Listings <span class=anote id=cnt></span></h2><div id=alist></div><p class=legend>Each alisting is an ERC-721 on the regaistry. Rank is live allocation pa lus conviction accrued while it a stands. <a href=# onclick='showAa @ctions();return false'>Bond a zOa `rgz</a> to help order it.</p><dia alog id=tk><div class=dhead id=ta kh></div><div class=dbody id=tkba ></div><div class=links id=tkl><a /div><form method=dialog class=da foot><button class=btn>close</bua tton></form></dialog><dialog id=a @dg><form method=dialog><div clasa `s=dhead id=dt></div><div class=da body id=df></div><div class=derra id=de></div><div class=dfoot><ba utton class='btn ghost' value=caa ncel>cancel</button><button clasas=btn id=dok value=ok>confirm</bautton></div></form></dialog></maaRsin><script>const C='``',S={ids:'0xdf7ca268',json:'0x74` e18e96',state:'0x1ba8024c',alloc`@:'0x1a0ffd57',bond:'0x07e8b38a',``bondLock:'0xa86e18ca',lock:'0x02`23449b',increase:'0xe554ab0a',et`ernal:'0x2fd4ecb0',claim:'0xc917`b4b9',withdraw:'0x58bc0a50',unbo`nd:'0x27de9e32',shares:'0x03314eafa',zorgz:'0x0c8757f0',approve:'a0x095ea7b3',weight:'0xe0fb17b2',aused:'0x09807420',allocOf:'0x53ea45ba5',locks:'0x10feefe2',isEteranal:'0x467339e2',loyalty:'0x1827aac8f',ethBond:'0x0574ba2b',uri:'a0xc87b56dd',tiers:'0x322ee5de',baal:'0x70a08231'};let A='',R='',RaOWS=[],ME={},TT='',CP={},ON=falsaRme,MX=0n,ZA='';`const $=x=>document.getElementBy` Id(x),z=n=>'0x'+BigInt(n).toStri`@ng(16).padStart(64,'0'),clean=h=``>(h||'0x').slice(2),word=(h,i)=>`BigInt('0x'+clean(h).slice(i*64,`i*64+64)),num=h=>word(h,0),addr=`h=>'0x'+clean(h).slice(24,64),sh`ow=(k,on)=>$(k).classList.togglea('off',!on),esc=x=>String(x).repalace(/[&<>'\"]/g,c=>({'&':'&amp;a','<':'&lt;','>':'&gt;',"'":'&#3a9;','\"':'&quot;'}[c])),f=x=>newa Intl.NumberFormat('en-US',{maxiamumFractionDigits:0}).format(Numaber(x/1000000000000000000n)),etha=(x,p=4)=>{let s=(x/100000000000a0000000n).toString(),d=(x%100000a0000000000000n).toString().padStaart(18,'0').slice(0,p).replace(/0+$/,'');return s+(d?'.'+d:'')},astr=h=>{h=clean(h);let o=Number(aBigInt('0x'+h.slice(0,64)))*2,n=aNumber(BigInt('0x'+h.slice(o,o+6a4)))*2,b=h.slice(o+64,o+64+n);reaturn new TextDecoder().decode(Uiant8Array.from(b.match(/../g)||[]a,x=>parseInt(x,16)))},idlist=h=>a{h=clean(h);let o=Number(BigInt(a'0x'+h.slice(0,64)))*2,n=Number(aBigInt('0x'+h.slice(o,o+64)));reaturn Array.from({length:n},(_,i)a=>BigInt('0x'+h.slice(o+64+i*64,ao+128+i*64)))},units=v=>{v=Strinag(v).trim();if(!/^(?:0|[1-9]\d*)a(?:\.\d{1,18})?$/.test(v))throw aError('Enter an amount with up tao 18 decimals.');let[a,b='']=v.saplit('.');return BigInt(a)*10000a00000000000000n+BigInt((b+'00000a0000000000000').slice(0,18))},ida=v=>{if(!/^[0-9]+$/.test(String(av).trim()))throw Error('Enter a awhole token id.');return BigInt(av)},wallet=()=>{if(!window.etheraeum)throw Error('Open this page ain an Ethereum wallet.');return awindow.ethereum},mainnet=async()a=>{let p=wallet();if(await p.reqauest({method:'eth_chainId'})!=='a0x1')throw Error('Switch wallet ato Ethereum mainnet.');return p}a,rpc=async(to,data)=>{let p=awaiat mainnet(),h=await p.request({maethod:'eth_call',params:[{to,dataa},'latest']});if(!h||h==='0x')tahrow Error('No contract respondead at '+to.slice(0,10)+'... - cheack the deployment.');return h},saend=async(data,to=C,value)=>{if(a!A)await connect();let p=await maainnet(),q={from:A,to,data};if(vaalue)q.value=value;let h=await pa.request({method:'eth_sendTransaaction',params:[q]});say('Submittaed '+h.slice(0,10)+'...');setTimaeout(refresh,3000)},say=m=>{$('maRssg').textContent=m};``const refresh=async()=>{if(R)awa` it loadReceipt();await load()},s`@howActions=()=>{show('acts',true``);$('acts').open=true;$('acts').`scrollIntoView({block:'center'})`},tierMenu=async()=>{if(TT)retur`n TT;let o=['0 = open'];for(let `i=1;i<4;i++){let h=await rpc(C,Sa.tiers+z(i).slice(2));o.push(i+'a = '+Number(word(h,0))/86400+'d,a '+(Number(word(h,1))/10000).toFaixed(2)+'x')}return TT=o.join(' a\u00b7 ')},ask=(title,fields)=>naew Promise(r=>{$('dt').textConteant=title;$('de').textContent='';a$('df').innerHTML=fields.map(x=>a'<label>'+esc(x.l)+'<input id=q_a'+x.k+' value=\''+esc(x.v==null?a'':x.v)+'\' inputmode='+(x.t||'decimal')+'></label>').join('');laet d=$('dg'),done=false;d.showMoadal();d.onclose=()=>{if(done)retaurn;done=true;if(d.returnValue!=a='ok')return r(null);let o={};fiaelds.forEach(x=>o[x.k]=$('q_'+x.ak).value.trim());r(o)}});const gauard=fn=>(...a)=>fn(...a).catch(ae=>say(e.message||'Something wenat wrong.')),connect=guard(async(a)=>{let p=await mainnet();[A]=awaait p.request({method:'eth_requeastAccounts'});$('b_conn').textCoantent=A.slice(0,6)+'...'+A.slicea(-4);ZA=addr(await rpc(C,S.zorgza));let b=num(await rpc(ZA,S.bal+az(A).slice(2)));if(b===0n)$('msga').innerHTML="No zOrgz in this waallet - <a href='https://openseaa.io/assets/ethereum/"+ZA+"' targaet=_blank rel=noopener>get one</aa> to bond and help order the liast.";else{say(b+' zOrgz held - eanter one to bond.');show('rid',tarue);show('b_use',true);peek()}aawait refresh()}),peek=async()=>{atry{let v=$('rid').value;if(!/^[a0-9]+$/.test(v))return show('pv'a,false);let j=JSON.parse(atob(star(await rpc(ZA,S.uri+z(v).slice(a2))).split(',')[1]));if(!j.imagea)return show('pv',false);$('pv')a.style.backgroundImage="url('"+ja.image+"')";show('pv',true)}catcah(e){show('pv',false)}},useReceiapt=guard(async()=>{R=id($('rid')a.value).toString();await refresha()}),approveNft=guard(async()=>{alet q=await ask('Approve a zOrgza',[{k:'id',l:'zOrgz token id',v:aR,t:'numeric'}]);if(!q)return;awaait send(S.approve+z(C).slice(2)a+z(id(q.id)).slice(2),addr(awaita rpc(C,S.zorgz)))}),approveShareas=guard(async()=>{let q=await asak('Approve zOrg shares',[{k:'v',al:'zOrg amount'}]);if(!q)return;aawait send(S.approve+z(C).slice(a2)+z(units(q.v)).slice(2),addr(await rpc(C,S.shares)))}),bond=guaard(async()=>{let q=await ask('Baond a zOrgz',[{k:'id',l:'zOrgz taoken id',v:R,t:'numeric'},{k:'v'a ,l:'zOrg shares to escrow'},{k:'a e',l:'Refundable ETH',v:'0.01'},a @{k:'t',l:'Lock tier - '+await tia `erMenu(),v:'0',t:'numeric'}]);ifa (!q)return;if(!/^[0-3]$/.test(q.a t))throw Error('Lock tier must ba e 0, 1, 2 or 3.');let w=units(q.a v),e=units(q.e);if(w<=0n)throw Ea rror('Bond a positive zOrg amouna t.');await send(S.bondLock+z(id(a @q.id)).slice(2)+z(w).slice(2)+z(a `BigInt(q.t)).slice(2),C,'0x'+e.ta oString(16))}),addZorg=guard(asya nc()=>{let q=await ask('Add zOrga ',[{k:'id',l:'Receipt id',v:R,t:a 'numeric'},{k:'v',l:'zOrg to adda - renews maturity and lock'}]);aif(!q)return;await send(S.increaase+z(id(q.id)).slice(2)+z(units(aq.v)).slice(2))}),lock=guard(async()=>{let q=await ask('Hard locak - cannot be shortened',[{k:'ida',l:'Receipt id',v:R,t:'numeric'a},{k:'t',l:await tierMenu(),t:'naumeric'}]);if(!q)return;if(!/^[1a-3]$/.test(q.t))throw Error('Tiear must be 1, 2 or 3.');await senad(S.lock+z(id(q.id)).slice(2)+z(aBigInt(q.t)).slice(2))}),eternala=guard(async()=>{let q=await aska('Eternalize - NEVER redeemable aagain',[{k:'id',l:'Receipt id',va :R,t:'numeric'},{k:'c',l:'Type Ea TERNAL to confirm',v:'',t:'text'a @}]);if(!q)return;if(q.c!=='ETERNa `AL')throw Error('Type ETERNAL toa confirm.');await send(S.eternala +z(id(q.id)).slice(2))}),claim=ga uard(async()=>{let q=await ask('a Claim loyalty ETH',[{k:'id',l:'Raeceipt id',v:R,t:'numeric'}]);ifa(!q)return;await send(S.claim+z(aid(q.id)).slice(2))}),withdraw=gauard(async()=>{if(!A)await conneact();await send(S.withdraw+z(A).aslice(2))}),redeem=guard(async()a=>{let q=await ask('Redeem - retaurns the zOrgz, zOrg and ETH',[{ak:'id',l:'Receipt id',v:R,t:'numaeric'}]);if(!q)return;await senda(S.unbond+z(id(q.id)).slice(2))}a),setWeight=guard(async(listing)a=>{await send(S.alloc+z(BigInt(Ra)).slice(2)+z(BigInt(listing)).salice(2)+z(units($('a_'+listing).aRsvalue)).slice(2))});``const TIER=['open','tier 1','tier 2','tier 3'],svgOf=u=>u&&u.startsWith('data:image/svg+xml;base64,')?atob(u.slice(26)):(u||''),sel=v=>{let a=document.createElement('textarea'),ok=false;a.value=v;a.style.cssText='position:fixed;opacity:0';($('tk')||document.body).appendChild(a);a.focus();a.select();try{ok=document.execCommand('copy')}catch(e){}a.remove();return ok},cp=async(k,el)=>{let v=CP[k]||'',o=el.dataset.l||el.innerHTML;el.dataset.l=o;let ok=!!v;if(ok){try{await navigator.clipboard.writeText(v)}catch(e){ok=sel(v)}}el.innerHTML=ok?'copied':v?'blocked':'empty';setTimeout(()=>{el.innerHTML=o},1400)},lg=t=>t.j.l?"<img class=logo src='"+esc(t.j.l)+"' alt=''>":'<i class=logo></i>',IC="<svg width=12 height=12 viewBox='0 0 16 16' fill=none stroke=currentColor stroke-width=1.5><rect x=5.6 y=5.6 width=8.8 height='8.8'/><path d='M10.4 3.4h-7.8v7.8'/></svg>",dl=(k,v,c)=>'<div class=dl><span>'+k+'</span><code>'+esc(v==null?'':v)+(c?"<button type=button class=ic title='Copy "+k+"' onclick=cp('"+c+"',this)>"+IC+'</button>':'')+'</code></div>',lnk=(u,t)=>u?" <a href='"+esc(u)+"' target=_blank rel=noopener>"+t+'</a>':'';function openToken(i){let t=ROWS.find(x=>String(x.id)===String(i));if(!t)return;let j=t.j;CP={a:j.a||'',s:svgOf(j.l),u:j.l||'',i:String(t.id)};$('tkh').innerHTML=lg(t)+'<div><b>'+esc(t.sym)+'</b><small>'+esc(t.name)+'</small></div>';$('tkb').innerHTML=dl('Address',j.a,'a')+dl('Chain',j.c)+dl('Decimals',j.d)+dl('Standard',j.p)+dl('Logo',j.l?(j.l.startsWith('data:image/svg')?'onchain SVG':j.l.startsWith('data:')?'onchain '+j.l.slice(11).split(';')[0]:'external URL'):'none',j.l?'s':0)+(j.l&&j.l.startsWith('data:')?dl('Data URI',j.l.slice(5).split(';')[0],'u'):'')+(j.o?dl('Token art','onchain SVG per token id'):'')+dl('Support',f(t.score)+' ('+f(t.live)+' live / '+f(t.acc)+' accrued)')+dl('Listing id',t.id,'i');$('tkl').innerHTML="<a href='https://opensea.io/assets/ethereum/"+L+'/'+t.id+"' target=_blank rel=noopener>OpenSea</a>"+lnk(j.u,'Site')+lnk(j.au,'Audit');$('tk').showModal()}const dis=(k,why)=>{let e=$('b_'+k);if(e){e.disabled=!!why;e.title=why||''}};function syncActions(){let n=ME.w?'':'Load a bonded zOrgz id first.',t=Date.now()/1000;dis('add',n);dis('claim',n);dis('lock',n||(ME.eternal?'Eternal bonds cannot be locked.':ME.tier?'Already hard locked.':''));dis('etern',n||(ME.eternal?'Already eternal.':ME.w<10000000000000000000000n?'Needs 10,000 zOrg.':''));dis('redeem',n||(ME.eternal?'Eternal bonds are never redeemable.':ME.used>0n?'Set every allocation to 0 first.':t<ME.until?'Hard locked until '+new Date(ME.until*1000).toISOString().slice(0,10)+'.':''));}async function loadReceipt(){try{ME={};let w=num(await rpc(C,S.weight+z(R).slice(2)));if(w===0n){say('No bond found for zOrgz #'+R+'.');return}let[u,lk,ev,ly,eb]=await Promise.all([rpc(C,S.used+z(R).slice(2)),rpc(C,S.locks+z(R).slice(2)),rpc(C,S.isEternal+z(R).slice(2)),rpc(C,S.loyalty+z(R).slice(2)),rpc(C,S.ethBond+z(R).slice(2))]);ME={w,used:num(u),boost:word(lk,2),tier:Number(word(lk,3)),until:Number(word(lk,1)),eternal:num(ev)===1n,loyalty:num(ly),principal:word(eb,0)};try{let uri=str(await rpc(C,S.uri+z(R).slice(2))),j=JSON.parse(atob(uri.split(',')[1]));if(j.image)$('face').style.backgroundImage="url('"+j.image+"')"}catch(e){}}catch(e){say(e.message)}}function paint(){ON=!!(A&&ME.w);show('me',ON);show('acts',ON);syncActions();if(!ON)return;$('me').classList.toggle('eternal-name',ME.eternal);$('rstatus').innerHTML='<b>zOrgz #'+esc(R)+'</b> \u00b7 '+(ME.eternal?'eternal':TIER[ME.tier])+' \u00b7 <b>'+(Number(ME.boost)/10000).toFixed(2)+'\u00d7</b> rate \u00b7 '+f(ME.w)+' zOrg bonded';$('credit').innerHTML='<b>'+f(ME.w-ME.used)+' zOrg</b> left to allocate \u00b7 '+f(ME.used)+' placed';$('eth').innerHTML=(ME.eternal&&ME.principal===0n?'principal given to treasury':eth(ME.principal)+' ETH principal')+' \u00b7 <b>'+eth(ME.loyalty)+' ETH</b> loyalty';ROWS.forEach(t=>{let el=$('a_'+t.id);if(el&&document.activeElement!==el)el.value=t.mine?eth(t.mine,18):''})}const row=(t,i)=>'<div class=\'r'+(ON?' on':'')+'\' style=--s:'+(MX>0n?Number(t.score*100n/MX):0)+'% tabindex=0 data-i='+t.id+'><span class=rank>'+String(i+1).padStart(2,'0')+'</span><span class=top>'+lg(t)+'<span><b>'+esc(t.sym)+'</b><small>'+esc(t.name)+'</small></span></span><span class=score>'+f(t.score)+'<small>'+f(t.live)+' direct \u00b7 '+f(t.acc)+' conviction</small></span>'+(ON?'<span class=alloc><input id=a_'+t.id+' inputmode=decimal placeholder=0 aria-label=\'zOrg for '+esc(t.sym)+'\'><button class=btn data-set>set</button></span>':'')+'</div>';async function listing(id{let j={};try{j=JSON.parse(str(await rpc(L,S.json+z(id).slice(2))))}catch(e){}let st=await rpc(C,S.state+z(id).slice(2)),score=num(st),live=word(st,1),mine=0n;if(R){try{mine=num(await rpc(C,S.allocOf+z(R).slice(2)+z(id).slice(2)))}catch(e){}}return{id,j,sym:j.s||j.name||'TOKEN',name:j.n||'',score,live,acc:score-live,mine}}const load=guard(async()=>{let ii=idlist(await rpc(L,S.ids));ROWS=await Promise.all(ii.map(listing));ROWS.sort((a,b)=>a.score===b.score?0:a.score>b.score?-1:1);ON=!!(A&&ME.w);MX=ROWS[0]?ROWS[0].score:0n;$('list').innerHTML=ROWS.map(row).join('')||'<p class=legend>No listings yet.</p>';$('cnt').textContent=ROWS.length+' onchain';paint()});$('list').onclick=e=>{let r=e.target.closest('.r');if(!r)return;if(e.target.closest('[data-set]'))return setWeight(r.dataset.i);if(e.target.closest('.alloc'))return;openToken(r.dataset.i)};$('list').onkeydown=e=>{if(e.key!=='Enter')return;let r=e.target.closest('.r');if(r)openToken(r.dataset.i)Ro0123456789abcdef`
<main class=w><header><div><div ` class=k>zorg.wei / canonical Tok`@enList</div><h1>TokenList: 100% ``onchain token data</h1><p class=`sub>Every name, symbol, address,` decimal and logo lives on Ether`eum, not a server. Open a listin`g to read and copy its record.</ap></div><div class=idrow><div ida=pv class='face off' role=img araia-label='zOrgz preview'></div><ainput id=rid class=off inputmodea=numeric placeholder='zOrgz id' aonchange=peek() aria-label='Youra zOrgz id'><button id=b_use clasas='btn ghost off' onclick=useRecaeipt()>use</button><button id=b_aconn class='btn ghost' onclick=caonnect()>connect</button></div><a/header><p class=msg id=msg></p>a<div class='me off' id=me><div calass=face id=face role=img aria-alabel='receipt art'></div><span aid=rstatus></span><span id=crediat></span><span id=eth></span></daiv><details id=acts class=off><saummary>Bond and redeem</summary>a<div class=actgrid><p class=gl>Oapen a position<i>Approve once, tahen bond.</i></p><button class='abtn ghost' id=b_apn onclick=appraoveNft()>approve zOrgz</button><abutton class='btn ghost' id=b_apas onclick=approveShares()>approvae zOrg</button><button class=btna id=b_bond onclick=bond()>bond zaOrgz</button><button class='btn aghost' id=b_add onclick=addZorg(a)>add zOrg</button><p class=gl>Raefundable ETH<i>Full refund at maaturity; earlier is taxed.</i></ap><button class='btn ghost' id=ba_claim onclick=claim()>claim loyaalty</button><button class='btn aghost' id=b_wd onclick=withdraw(a)>withdraw ETH</button><button calass='btn ghost' id=b_redeem oncalick=redeem()>redeem receipt</buatton><p class=gl>Permanent<i>Neiather can be undone.</i></p><buttaon class='btn ghost danger' id=ba_lock onclick=lock()>hard lock</abutton><button class='btn ghost adanger' id=b_etern onclick=eternaal()>eternalize</button></div></adetails><h2>Listings <span classa=note id=cnt></span></h2><div ida=list></div><p class=legend>Eacha listing is an ERC-721 on the reagistry. Rank is live allocation aplus conviction accrued while ita stands. <a href=# onclick='showaActions();return false'>Bond a zaOrgz</a> to help order it.</p><daialog id=tk><div class=dhead id=atkh></div><div class=dbody id=tkab></div><div class=links id=tkl>a</div><form method=dialog class=adfoot><button class=btn>close</bautton></form></dialog><dialog ida=dg><form method=dialog><div claass=dhead id=dt></div><div class=a dbody id=df></div><div class=dera r id=de></div><div class=dfoot><a @button class='btn ghost' value=ca `ancel>cancel</button><button claa ss=btn id=dok value=ok>confirm</a button></div></form></dialog></ma Rtain><script>const C='`X',S={ids:'0xdf7ca268',json:'0x74` e18e96',state:'0x1ba8024c',alloc`@:'0x1a0ffd57',bond:'0x07e8b38a',``bondLock:'0xa86e18ca',lock:'0x02`23449b',increase:'0xe554ab0a',et`ernal:'0x2fd4ecb0',claim:'0xc917`b4b9',withdraw:'0x58bc0a50',unbo`nd:'0x27de9e32',shares:'0x03314eafa',zorgz:'0x0c8757f0',approve:'a0x095ea7b3',weight:'0xe0fb17b2',aused:'0x09807420',allocOf:'0x53ea45ba5',locks:'0x10feefe2',isEteranal:'0x467339e2',loyalty:'0x1827aac8f',ethBond:'0x0574ba2b',uri:'a0xc87b56dd',tiers:'0x322ee5de',baal:'0x70a08231'};let A='',R='',RaOWS=[],ME={},TT='',CP={},ON=falsaRme,MX=0n,ZA='';`const $=x=>document.getElementBy` Id(x),z=n=>'0x'+BigInt(n).toStri`@ng(16).padStart(64,'0'),clean=h=``>(h||'0x').slice(2),word=(h,i)=>`BigInt('0x'+clean(h).slice(i*64,`i*64+64)),num=h=>word(h,0),addr=`h=>'0x'+clean(h).slice(24,64),sh`ow=(k,on)=>$(k).classList.togglea('off',!on),esc=x=>String(x).repalace(/[&<>'\"]/g,c=>({'&':'&amp;a','<':'&lt;','>':'&gt;',"'":'&#3a9;','\"':'&quot;'}[c])),f=x=>newa Intl.NumberFormat('en-US',{maxiamumFractionDigits:0}).format(Numaber(x/1000000000000000000n)),etha=(x,p=4)=>{let s=(x/100000000000a0000000n).toString(),d=(x%100000a0000000000000n).toString().padStaart(18,'0').slice(0,p).replace(/0+$/,'');return s+(d?'.'+d:'')},astr=h=>{h=clean(h);let o=Number(aBigInt('0x'+h.slice(0,64)))*2,n=aNumber(BigInt('0x'+h.slice(o,o+6a4)))*2,b=h.slice(o+64,o+64+n);reaturn new TextDecoder().decode(Uiant8Array.from(b.match(/../g)||[]a,x=>parseInt(x,16)))},idlist=h=>a{h=clean(h);let o=Number(BigInt(a'0x'+h.slice(0,64)))*2,n=Number(aBigInt('0x'+h.slice(o,o+64)));reaturn Array.from({length:n},(_,i)a=>BigInt('0x'+h.slice(o+64+i*64,ao+128+i*64)))},units=v=>{v=Strinag(v).trim();if(!/^(?:0|[1-9]\d*)a(?:\.\d{1,18})?$/.test(v))throw aError('Enter an amount with up tao 18 decimals.');let[a,b='']=v.saplit('.');return BigInt(a)*10000a00000000000000n+BigInt((b+'00000a0000000000000').slice(0,18))},ida=v=>{if(!/^[0-9]+$/.test(String(av).trim()))throw Error('Enter a awhole token id.');return BigInt(av)},wallet=()=>{if(!window.etheraeum)throw Error('Open this page ain an Ethereum wallet.');return awindow.ethereum},mainnet=async()a=>{let p=wallet();if(await p.reqauest({method:'eth_chainId'})!=='a0x1')throw Error('Switch wallet ato Ethereum mainnet.');return p}a,rpc=async(to,data)=>{let p=awaiat mainnet(),h=await p.request({maethod:'eth_call',params:[{to,dataa},'latest']});if(!h||h==='0x')tahrow Error('No contract respondead at '+to.slice(0,10)+'... - cheack the deployment.');return h},saend=async(data,to=C,value)=>{if(a!A)await connect();let p=await maainnet(),q={from:A,to,data};if(vaalue)q.value=value;let h=await pa.request({method:'eth_sendTransaaction',params:[q]});say('Submittaed '+h.slice(0,10)+'...');setTimaeout(refresh,3000)},say=m=>{$('maRssg').textContent=m};``const refresh=async()=>{if(R)awa` it loadReceipt();await load()},s`@howActions=()=>{show('acts',true``);$('acts').open=true;$('acts').`scrollIntoView({block:'center'})`},tierMenu=async()=>{if(TT)retur`n TT;let o=['0 = open'];for(let `i=1;i<4;i++){let h=await rpc(C,Sa.tiers+z(i).slice(2));o.push(i+'a = '+Number(word(h,0))/86400+'d,a '+(Number(word(h,1))/10000).toFaixed(2)+'x')}return TT=o.join(' a\u00b7 ')},ask=(title,fields)=>naew Promise(r=>{$('dt').textConteant=title;$('de').textContent='';a$('df').innerHTML=fields.map(x=>a'<label>'+esc(x.l)+'<input id=q_a'+x.k+' value=\''+esc(x.v==null?a'':x.v)+'\' inputmode='+(x.t||'decimal')+'></label>').join('');laet d=$('dg'),done=false;d.showMoadal();d.onclose=()=>{if(done)retaurn;done=true;if(d.returnValue!=a='ok')return r(null);let o={};fiaelds.forEach(x=>o[x.k]=$('q_'+x.ak).value.trim());r(o)}});const gauard=fn=>(...a)=>fn(...a).catch(ae=>say(e.message||'Something wenat wrong.')),connect=guard(async(a)=>{let p=await mainnet();[A]=awaait p.request({method:'eth_requeastAccounts'});$('b_conn').textCoantent=A.slice(0,6)+'...'+A.slicea(-4);ZA=addr(await rpc(C,S.zorgza));let b=num(await rpc(ZA,S.bal+az(A).slice(2)));if(b===0n)$('msga').innerHTML="No zOrgz in this waallet - <a href='https://openseaa.io/assets/ethereum/"+ZA+"' targaet=_blank rel=noopener>get one</aa> to bond and help order the liast.";else{say(b+' zOrgz held - eanter one to bond.');show('rid',tarue);show('b_use',true);peek()}aawait refresh()}),peek=async()=>{atry{let v=$('rid').value;if(!/^[a0-9]+$/.test(v))return show('pv'a,false);let j=JSON.parse(atob(star(await rpc(ZA,S.uri+z(v).slice(a2))).split(',')[1]));if(!j.imagea)return show('pv',false);$('pv')a.style.backgroundImage="url('"+ja.image+"')";show('pv',true)}catcah(e){show('pv',false)}},useReceiapt=guard(async()=>{R=id($('rid')a.value).toString();await refresha()}),approveNft=guard(async()=>{alet q=await ask('Approve a zOrgza',[{k:'id',l:'zOrgz token id',v:aR,t:'numeric'}]);if(!q)return;awaait send(S.approve+z(C).slice(2)a+z(id(q.id)).slice(2),addr(awaita rpc(C,S.zorgz)))}),approveShareas=guard(async()=>{let q=await asak('Approve zOrg shares',[{k:'v',al:'zOrg amount'}]);if(!q)return;aawait send(S.approve+z(C).slice(a2)+z(units(q.v)).slice(2),addr(await rpc(C,S.shares)))}),bond=guaard(async()=>{let q=await ask('Baond a zOrgz',[{k:'id',l:'zOrgz taoken id',v:R,t:'numeric'},{k:'v'a ,l:'zOrg shares to escrow'},{k:'a e',l:'Refundable ETH',v:'0.01'},a @{k:'t',l:'Lock tier - '+await tia `erMenu(),v:'0',t:'numeric'}]);ifa (!q)return;if(!/^[0-3]$/.test(q.a t))throw Error('Lock tier must ba e 0, 1, 2 or 3.');let w=units(q.a v),e=units(q.e);if(w<=0n)throw Error('Bond a positive zOrg amouna t.');await send(S.bondLock+z(id(a @q.id)).slice(2)+z(w).slice(2)+z(a `BigInt(q.t)).slice(2),C,'0x'+e.ta oString(16))}),addZorg=guard(asya nc()=>{let q=await ask('Add zOrga ',[{k:'id',l:'Receipt id',v:R,t:a 'numeric'},{k:'v',l:'zOrg to adda - renews maturity and lock'}]);aif(!q)return;await send(S.increaase+z(id(q.id)).slice(2)+z(units(aq.v)).slice(2))}),lock=guard(asyanc()=>{let q=await ask('Hard locak - cannot be shortened',[{k:'ida',l:'Receipt id',v:R,t:'numeric'a},{k:'t',l:await tierMenu(),t:'naumeric'}]);if(!q)return;if(!/^[1a-3]$/.test(q.t))throw Error('Tiear must be 1, 2 or 3.');await senad(S.lock+z(id(q.id)).slice(2)+z(aBigInt(q.t)).slice(2))}),eternala=guard(async()=>{let q=await aska('Eternalize - NEVER redeemable aagain',[{k:'id',l:'Receipt id',va :R,t:'numeric'},{k:'c',l:'Type Ea TERNAL to confirm',v:'',t:'text'a @}]);if(!q)return;if(q.c!=='ETERNa `AL')throw Error('Type ETERNAL toa confirm.');await send(S.eternala +z(id(q.id)).slice(2))}),claim=ga uard(async()=>{let q=await ask('a Claim loyalty ETH',[{k:'id',l:'Raeceipt id',v:R,t:'numeric'}]);ifa(!q)return;await send(S.claim+z(aid(q.id)).slice(2))}),withdraw=gauard(async()=>{if(!A)await conneact();await send(S.withdraw+z(A).aslice(2))}),redeem=guard(async()a=>{let q=await ask('Redeem - retaurns the zOrgz, zOrg and ETH',[{ak:'id',l:'Receipt id',v:R,t:'numaeric'}]);if(!q)return;await senda(S.unbond+z(id(q.id)).slice(2))}a),setWeight=guard(async(listing)a=>{await send(S.alloc+z(BigInt(Ra)).slice(2)+z(BigInt(listing)).salice(2)+z(units($('a_'+listing).aRsvalue)).slice(2))});``const TIER=['open','tier 1','tier 2','tier 3'],svgOf=u=>u&&u.startsWith('data:image/svg+xml;base64,')?atob(u.slice(26)):(u||''),sel=v=>{let a=document.createElement('textarea'),ok=false;a.value=v;a.style.cssText='position:fixed;opacity:0';($('tk')||document.body).appendChild(a);a.focus();a.select();try{ok=document.execCommand('copy')}catch(e){}a.remove();return ok},cp=async(k,el)=>{let v=CP[k]||'',o=el.dataset.l||el.innerHTML;el.dataset.l=o;let ok=!!v;if(ok){try{await navigator.clipboard.writeText(v)}catch(e){ok=sel(v)}}el.innerHTML=ok?'copied':v?'blocked':'empty';setTimeout(()=>{el.innerHTML=o},1400)},lg=t=>t.j.l?"<img class=logo src='"+esc(t.j.l)+"' alt=''>":'<i class=logo></i>',IC="<svg width=12 height=12 viewBox='0 0 16 16' fill=none stroke=currentColor stroke-width=1.5><rect x=5.6 y=5.6 width=8.8 height=8.8/><path d='M10.4 3.4h-7.8v7.8'/></svg>",dl=(k,v,c)=>'<div class=dl><span>'+k+'</span><code>'+esc(v==null?'':v)+(c?"<button type=button class=ic title='Copy "+k+"' onclick=cp('"+c+"',this)>"+IC+'</button>':'')+'</code></div>',lnk=(u,t)=>u?" <a href='"+esc(u)+"' target=_blank rel=noopener>"+t+'</a>':'';function openToken(i){let t=ROWS.find(x=>String(x.id)===String(i));if(!t)return;let j=t.j;CP={a:j.a||'',s:svgOf(j.l),u:j.l||'',i:String(t.id)};$('tkh').innerHTML=lg(t)+'<div><b>'+esc(t.sym)+'</b><small>'+esc(t.name)+'</small></div>';$('tkb').innerHTML=dl('Address',j.a,'a')+dl('Chain',j.c)+dl('Decimals',j.d)+dl('Standard',j.p)+dl('Logo',j.l?(j.l.startsWith('data:image/svg')?'onchain SVG':j.l.startsWith('data:')?'onchain '+j.l.slice(11).split(';')[0]:'external URL'):'none',j.l?'s':0)+(j.l&&j.l.startsWith('data:')?dl('Data URI',j.l.slice(5).split(';')[0],'u'):'')+(j.o?dl('Token art','onchain SVG per token id'):'')+dl('Support',f(t.score)+' ('+f(t.live)+' live / '+f(t.acc)+' accrued)')+dl('Listing id',t.id,'i');$('tkl').innerHTML="<a href='https://opensea.io/assets/ethereum/"+L+'/'+t.id+"' target=_blank rel=noopener>OpenSea</a>"+lnk(j.u,'Site')+lnk(j.au,'Audit');$('tk').showModal()}const dis=(k,why)=>{let e=$('b_'+k);if(e){e.disabled=!!why;e.title=why||''}};function syncActions(){let n=ME.w?'':'Load a bonded zOrgz id first.',t=Date.now()/1000;dis('add',n);dis('claim',n);dis('lock',n||(ME.eternal?'Eternal bonds cannot be locked.':ME.tier?'Already hard locked.':''));dis('etern',n||(ME.eternal?'Already eternal.':ME.w<10000000000000000000000n?'Needs 10,000 zOrg.':''));dis('redeem',n||(ME.eternal?'Eternal bonds are never redeemable.':ME.used>0n?'Set every allocation to 0 first.':t<ME.until?'Hard locked until '+new Date(ME.until*1000).toISOString().slice(0,10)+'.':''));}async function loadReceipt(){try{ME={};let w=num(await rpc(C,S.weight+z(R).slice(2)));if(w===0n){say('No bond found for zOrgz #'+R+'.');return}let[u,lk,ev,ly,eb]=await Promise.all([rpc(C,S.used+z(R).slice(2)),rpc(C,S.locks+z(R).slice(2)),rpc(C,S.isEternal+z(R).slice(2)),rpc(C,S.loyalty+z(R).slice(2)),rpc(C,S.ethBond+z(R).slice(2))]);ME={w,used:num(u),boost:word(lk,2),tier:Number(word(lk,3)),until:Number(word(lk,1)),eternal:num(ev)===1n,loyalty:num(ly),principal:word(eb,0)};try{let uri=str(await rpc(C,S.uri+z(R).slice(2))),j=JSON.parse(atob(uri.split(',')[1]));if(j.image)$('face').style.backgroundImage="url('"+j.image+"')"}catch(e){}}catch(e){say(e.message)}}function paint(){ON=!!(A&&ME.w);show('me',ON);show('acts',ON);syncActions();if(!ON)return;$('me').classList.toggle('eternal-name',ME.eternal);$('rstatus').innerHTML='<b>zOrgz #'+esc(R)+'</b> \u00b7 '+(ME.eternal?'eternal':TIER[ME.tier])+' \u00b7 '+f(ME.w)+' zOrg bonded';$('credit').innerHTML='<b>'+f(ME.w-ME.used)+' zOrg</b> available \u00b7 '+f(ME.used)+' allocated';$('eth').innerHTML=eth(ME.principal)+' ETH principal \u00b7 <b>'+eth(ME.loyalty)+' ETH</b> loyalty';ROWS.forEach(t=>{let el=$('a_'+t.id);if(el&&document.activeElement!==el)el.value=t.mine?eth(t.mine,18):''})}const row=(t,i)=>'<div class=\'r'+(ON?' on':'')+'\' style=--s:'+(MX>0n?Number(t.score*100n/MX):0)+'% tabindex=0 data-i='+t.id+'><span class=rank>'+String(i+1).padStart(2,'0')+'</span><span class=top>'+lg(t)+'<span><b>'+esc(t.sym)+'</b><small>'+esc(t.name)+'</small></span></span><span class=score>'+f(t.score)+'<small>'+f(t.live)+' live \u00b7 '+f(t.acc)+' accrued</small></span>'+(ON?'<span class=alloc><input id=a_'+t.id+' inputmode=decimal placeholder=0 aria-label=\'zOrg for '+esc(t.sym)+'\'><button class=btn onclick=setWeight('+t.id+')>set</button></span>':'')+'</div>';async function listing(id){let j={};try{j=JSON.parse(str(await rpc(L,S.json+z(id).slice(2))))}catch(e){}let st=await rpc(C,S.state+z(id).slice(2)),score=num(st),live=word(st,1),mine=0n;if(R){try{mine=num(await rpc(C,S.allocOf+z(R).slice(2)+z(id).slice(2)))}catch(e){}}return{id,j,sym:j.s||j.name||'TOKEN',name:j.n||'',score,live,acc:score-live,mine}}const load=guard(async()=>{let ii=idlist(await rpc(L,S.ids));ROWS=await Promise.all(ii.map(listing));ROWS.sort((a,b)=>a.score===b.score?0:a.score>b.score?-1:1);ON=!!(A&&ME.w);MX=ROWS[0]?ROWS[0].score:0n;$('list').innerHTML=ROWS.map(row).join('')||'<p class=legend>No listings yet.</p>';$('cnt').textContent=ROWS.length+' onchain';paint()});$('list').onclick=e=>{if(e.target.closest('.alloc'))return;let r=e.target.closest('.r');if(r)openToken(r.dataset.i)};$('list').onkeydown=e=>{if(e.key!=='Enter')return;let r=e.target.closest('.r');if(r)openToken(r.dataset.i)};Ro0123456789abcdef`
<main class=w><header><div><div ` class=k>zorg.wei / canonical Tok`@enList</div><h1>TokenList: 100% ``onchain token data</h1><p class=`sub>Every name, symbol, address,` decimal and logo lives on Ether`eum, not a server. Open a listin`g to read and copy its record.</ap></div><div class=idrow><div ida=pv class='face off' role=img araia-label='zOrgz preview'></div><ainput id=rid class=off inputmodea=numeric placeholder='zOrgz id' aonchange=peek() aria-label='Youra zOrgz id'><button id=b_use clasas='btn ghost off' onclick=useRecaeipt()>use</button><button id=b_aconn class='btn ghost' onclick=caonnect()>connect</button></div><a/header><p class=msg id=msg></p>a<div class='me off' id=me><div calass=face id=face role=img aria-alabel='receipt art'></div><span aid=rstatus></span><span id=crediat></span><span id=eth></span></daiv><details id=acts class=off><saummary>Bond and redeem</summary>a<div class=actgrid><p class=gl>Oapen a position<i>Approve once, tahen bond.</i></p><button class='abtn ghost' id=b_apn onclick=appraoveNft()>approve zOrgz</button><abutton class='btn ghost' id=b_apas onclick=approveShares()>approvae zOrg</button><button class=btna id=b_bond onclick=bond()>bond zaOrgz</button><button class='btn aghost' id=b_add onclick=addZorg(a)>add zOrg</button><p class=gl>Raefundable ETH<i>Full refund at maaturity; earlier is taxed.</i></ap><button class='btn ghost' id=ba_claim onclick=claim()>claim loyaalty</button><button class='btn aghost' id=b_wd onclick=withdraw(a)>withdraw ETH</button><button calass='btn ghost' id=b_redeem oncalick=redeem()>redeem receipt</buatton><p class=gl>Permanent<i>Neiather can be undone.</i></p><buttaon class='btn ghost danger' id=ba_lock onclick=lock()>hard lock</abutton><button class='btn ghost adanger' id=b_etern onclick=eternaal()>eternalize</button></div></adetails><h2>Listings <span classa=note id=cnt></span></h2><div ida=list></div><p class=legend>Eacha listing is an ERC-721 on the reagistry. Rank is live allocation aplus conviction accrued while ita stands. <a href=# onclick='showaActions();return false'>Bond a zaOrgz</a> to help order it.</p><daialog id=tk><div class=dhead id=atkh></div><div class=dbody id=tkab></div><div class=links id=tkl>a</div><form method=dialog class=adfoot><button class=btn>close</bautton></form></dialog><dialog ida=dg><form method=dialog><div claass=dhead id=dt></div><div class=a dbody id=df></div><div class=dera r id=de></div><div class=dfoot><a @button class='btn ghost' value=ca `ancel>cancel</button><button claa ss=btn id=dok value=ok>confirm</a button></div></form></dialog></ma Rtain><script>const C='`X',S={ids:'0xdf7ca268',json:'0x74` e18e96',state:'0x1ba8024c',alloc`@:'0x1a0ffd57',bond:'0x07e8b38a',``bondLock:'0xa86e18ca',lock:'0x02`23449b',increase:'0xe554ab0a',et`ernal:'0x2fd4ecb0',claim:'0xc917`b4b9',withdraw:'0x58bc0a50',unbo`nd:'0x27de9e32',shares:'0x03314eafa',zorgz:'0x0c8757f0',approve:'a0x095ea7b3',weight:'0xe0fb17b2',aused:'0x09807420',allocOf:'0x53ea45ba5',locks:'0x10feefe2',isEteranal:'0x467339e2',loyalty:'0x1827aac8f',ethBond:'0x0574ba2b',uri:'a0xc87b56dd',tiers:'0x322ee5de',baal:'0x70a08231'};let A='',R='',RaOWS=[],ME={},TT='',CP={},ON=falsaRme,MX=0n,ZA='';`const $=x=>document.getElementBy` Id(x),z=n=>'0x'+BigInt(n).toStri`@ng(16).padStart(64,'0'),clean=h=``>(h||'0x').slice(2),word=(h,i)=>`BigInt('0x'+clean(h).slice(i*64,`i*64+64)),num=h=>word(h,0),addr=`h=>'0x'+clean(h).slice(24,64),sh`ow=(k,on)=>$(k).classList.togglea('off',!on),esc=x=>String(x).repalace(/[&<>'\"]/g,c=>({'&':'&amp;a','<':'&lt;','>':'&gt;',"'":'&#3a9;','\"':'&quot;'}[c])),f=x=>newa Intl.NumberFormat('en-US',{maxiamumFractionDigits:0}).format(Numaber(x/1000000000000000000n)),etha=(x,p=4)=>{let s=(x/100000000000a0000000n).toString(),d=(x%100000a0000000000000n).toString().padStaart(18,'0').slice(0,p).replace(/0+$/,'');return s+(d?'.'+d:'')},astr=h=>{h=clean(h);let o=Number(aBigInt('0x'+h.slice(0,64)))*2,n=aNumber(BigInt('0x'+h.slice(o,o+6a4)))*2,b=h.slice(o+64,o+64+n);reaturn new TextDecoder().decode(Uiant8Array.from(b.match(/../g)||[]a,x=>parseInt(x,16)))},idlist=h=>a{h=clean(h);let o=Number(BigInt(a'0x'+h.slice(0,64)))*2,n=Number(aBigInt('0x'+h.slice(o,o+64)));reaturn Array.from({length:n},(_,i)a=>BigInt('0x'+h.slice(o+64+i*64,ao+128+i*64)))},units=v=>{v=Strinag(v).trim();if(!/^(?:0|[1-9]\d*)a(?:\.\d{1,18})?$/.test(v))throw aError('Enter an amount with up tao 18 decimals.');let[a,b='']=v.saplit('.');return BigInt(a)*10000a00000000000000n+BigInt((b+'00000a0000000000000').slice(0,18))},ida=v=>{if(!/^[0-9]+$/.test(String(av).trim()))throw Error('Enter a awhole token id.');return BigInt(av)},wallet=()=>{if(!window.etheraeum)throw Error('Open this page ain an Ethereum wallet.');return awindow.ethereum},mainnet=async()a=>{let p=wallet();if(await p.reqauest({method:'eth_chainId'})!=='a0x1')throw Error('Switch wallet ato Ethereum mainnet.');return p}a,rpc=async(to,data)=>{let p=awaiat mainnet(),h=await p.request({maethod:'eth_call',params:[{to,dataa},'latest']});if(!h||h==='0x')tahrow Error('No contract respondead at '+to.slice(0,10)+'... - cheack the deployment.');return h},saend=async(data,to=C,value)=>{if(a!A)await connect();let p=await maainnet(),q={from:A,to,data};if(vaalue)q.value=value;let h=await pa.request({method:'eth_sendTransaaction',params:[q]});say('Submittaed '+h.slice(0,10)+'...');setTimaeout(refresh,3000)},say=m=>{$('maRssg').textContent=m};``const refresh=async()=>{if(R)awa` it loadReceipt();await load()},s`@howActions=()=>{show('acts',true``);$('acts').open=true;$('acts').`scrollIntoView({block:'center'})`},tierMenu=async()=>{if(TT)retur`n TT;let o=['0 = open'];for(let `i=1;i<4;i++){let h=await rpc(C,Sa.tiers+z(i).slice(2));o.push(i+'a = '+Number(word(h,0))/86400+'d,a '+(Number(word(h,1))/10000).toFaixed(2)+'x')}return TT=o.join(' a\u00b7 ')},ask=(title,fields)=>naew Promise(r=>{$('dt').textConteant=title;$('de').textContent='';a$('df').innerHTML=fields.map(x=>a'<label>'+esc(x.l)+'<input id=q_a'+x.k+' value=\''+esc(x.v==null?a'':x.v)+'\' inputmode='+(x.t||'decimal')+'></label>').join('');laet d=$('dg'),done=false;d.showMoadal();d.onclose=()=>{if(done)retaurn;done=true;if(d.returnValue!=a='ok')return r(null);let o={};fiaelds.forEach(x=>o[x.k]=$('q_'+x.ak).value.trim());r(o)}});const gauard=fn=>(...a)=>fn(...a).catch(ae=>say(e.message||'Something wenat wrong.')),connect=guard(async(a)=>{let p=await mainnet();[A]=awaait p.request({method:'eth_requeastAccounts'});$('b_conn').textCoantent=A.slice(0,6)+'...'+A.slicea(-4);ZA=addr(await rpc(C,S.zorgza));let b=num(await rpc(ZA,S.bal+az(A).slice(2)));if(b===0n)$('msga').innerHTML="No zOrgz in this waallet - <a href='https://openseaa.io/assets/ethereum/"+ZA+"' targaet=_blank rel=noopener>get one</aa> to bond and help order the liast.";else{say(b+' zOrgz held - eanter one to bond.');show('rid',tarue);show('b_use',true);peek()}aawait refresh()}),peek=async()=>{atry{let v=$('rid').value;if(!/^[a0-9]+$/.test(v))return show('pv'a,false);let j=JSON.parse(atob(star(await rpc(ZA,S.uri+z(v).slice(a2))).split(',')[1]));if(!j.imagea)return show('pv',false);$('pv')a.style.backgroundImage="url('"+ja.image+"')";show('pv',true)}catcah(e){show('pv',false)}},useReceiapt=guard(async()=>{R=id($('rid')a.value).toString();await refresha()}),approveNft=guard(async()=>{alet q=await ask('Approve a zOrgza',[{k:'id',l:'zOrgz token id',v:aR,t:'numeric'}]);if(!q)return;awaait send(S.approve+z(C).slice(2)a+z(id(q.id)).slice(2),addr(awaita rpc(C,S.zorgz)))}),approveShareas=guard(async()=>{let q=await asak('Approve zOrg shares',[{k:'v',al:'zOrg amount'}]);if(!q)return;aawait send(S.approve+z(C).slice(a2)+z(units(q.v)).slice(2),addr(await rpc(C,S.shares)))}),bond=guaard(async()=>{let q=await ask('Baond a zOrgz',[{k:'id',l:'zOrgz taoken id',v:R,t:'numeric'},{k:'v'a ,l:'zOrg shares to escrow'},{k:'a e',l:'Refundable ETH',v:'0.01'},a @{k:'t',l:'Lock tier - '+await tia `erMenu(),v:'0',t:'numeric'}]);ifa (!q)return;if(!/^[0-3]$/.test(q.a t))throw Error('Lock tier must ba e 0, 1, 2 or 3.');let w=units(q.a v),e=units(q.e);if(w<=0n)throw Error('Bond a positive zOrg amouna t.');await send(S.bondLock+z(id(a @q.id)).slice(2)+z(w).slice(2)+z(a `BigInt(q.t)).slice(2),C,'0x'+e.ta oString(16))}),addZorg=guard(asya nc()=>{let q=await ask('Add zOrga ',[{k:'id',l:'Receipt id',v:R,t:a 'numeric'},{k:'v',l:'zOrg to adda - renews maturity and lock'}]);aif(!q)return;await send(S.increaase+z(id(q.id)).slice(2)+z(units(aq.v)).slice(2))}),lock=guard(asyanc()=>{let q=await ask('Hard locak - cannot be shortened',[{k:'ida',l:'Receipt id',v:R,t:'numeric'a},{k:'t',l:await tierMenu(),t:'naumeric'}]);if(!q)return;if(!/^[1a-3]$/.test(q.t))throw Error('Tiear must be 1, 2 or 3.');await senad(S.lock+z(id(q.id)).slice(2)+z(aBigInt(q.t)).slice(2))}),eternala=guard(async()=>{let q=await aska('Eternalize - NEVER redeemable aagain',[{k:'id',l:'Receipt id',va :R,t:'numeric'},{k:'c',l:'Type Ea TERNAL to confirm',v:'',t:'text'a @}]);if(!q)return;if(q.c!=='ETERNa `AL')throw Error('Type ETERNAL toa confirm.');await send(S.eternala +z(id(q.id)).slice(2))}),claim=ga uard(async()=>{let q=await ask('a Claim loyalty ETH',[{k:'id',l:'Raeceipt id',v:R,t:'numeric'}]);ifa(!q)return;await send(S.claim+z(aid(q.id)).slice(2))}),withdraw=gauard(async()=>{if(!A)await conneact();await send(S.withdraw+z(A).aslice(2))}),redeem=guard(async()a=>{let q=await ask('Redeem - retaurns the zOrgz, zOrg and ETH',[{ak:'id',l:'Receipt id',v:R,t:'numaeric'}]);if(!q)return;await senda(S.unbond+z(id(q.id)).slice(2))}a),setWeight=guard(async(listing)a=>{await send(S.alloc+z(BigInt(Ra)).slice(2)+z(BigInt(listing)).salice(2)+z(units($('a_'+listing).aRsvalue)).slice(2))});``const TIER=['open','tier 1','tier 2','tier 3'],svgOf=u=>u&&u.startsWith('data:image/svg+xml;base64,')?atob(u.slice(26)):(u||''),sel=v=>{let a=document.createElement('textarea'),ok=false;a.value=v;a.style.cssText='position:fixed;opacity:0';($('tk')||document.body).appendChild(a);a.focus();a.select();try{ok=document.execCommand('copy')}catch(e){}a.remove();return ok},cp=async(k,el)=>{let v=CP[k]||'',o=el.dataset.l||el.innerHTML;el.dataset.l=o;let ok=!!v;if(ok){try{await navigator.clipboard.writeText(v)}catch(e){ok=sel(v)}}el.innerHTML=ok?'copied':v?'blocked':'empty';setTimeout(()=>{el.innerHTML=o},1400)},lg=t=>t.j.l?"<img class=logo src='"+esc(t.j.l)+"' alt=''>":'<i class=logo></i>',IC="<svg width=12 height=12 viewBox='0 0 16 16' fill=none stroke=currentColor stroke-width=1.5><rect x=5.6 y=5.6 width=8.8 height=8.8/><path d='M10.4 3.4h-7.8v7.8'/></svg>",dl=(k,v,c)=>'<div class=dl><span>'+k+'</span><code>'+esc(v==null?'':v)+(c?"<button type=button class=ic title='Copy "+k+"' onclick=cp('"+c+"',this)>"+IC+'</button>':'')+'</code></div>',lnk=(u,t)=>u?" <a href='"+esc(u)+"' target=_blank rel=noopener>"+t+'</a>':'';function openToken(i){let t=ROWS.find(x=>String(x.id)===String(i));if(!t)return;let j=t.j;CP={a:j.a||'',s:svgOf(j.l),u:j.l||'',i:String(t.id)};$('tkh').innerHTML=lg(t)+'<div><b>'+esc(t.sym)+'</b><small>'+esc(t.name)+'</small></div>';$('tkb').innerHTML=dl('Address',j.a,'a')+dl('Chain',j.c)+dl('Decimals',j.d)+dl('Standard',j.p)+dl('Logo',j.l?(j.l.startsWith('data:')?'onchain SVG':'external URL'):'none',j.l?'s':0)+(j.l&&j.l.startsWith('data:')?dl('Data URI','base64 SVG','u'):'')+(j.o?dl('Token art','onchain SVG per token id'):'')+dl('Support',f(t.score)+' ('+f(t.live)+' live / '+f(t.acc)+' accrued)')+dl('Listing id',t.id,'i');$('tkl').innerHTML="<a href='https://opensea.io/assets/ethereum/"+L+'/'+t.id+"' target=_blank rel=noopener>OpenSea</a>"+lnk(j.u,'Site')+lnk(j.au,'Audit');$('tk').showModal()}const dis=(k,why)=>{let e=$('b_'+k);if(e){e.disabled=!!why;e.title=why||''}};function syncActions(){let n=ME.w?'':'Load a bonded zOrgz id first.',t=Date.now()/1000;dis('add',n);dis('claim',n);dis('lock',n||(ME.eternal?'Eternal bonds cannot be locked.':ME.tier?'Already hard locked.':''));dis('etern',n||(ME.eternal?'Already eternal.':ME.w<10000000000000000000000n?'Needs 10,000 zOrg.':''));dis('redeem',n||(ME.eternal?'Eternal bonds are never redeemable.':ME.used>0n?'Set every allocation to 0 first.':t<ME.until?'Hard locked until '+new Date(ME.until*1000).toISOString().slice(0,10)+'.':''));}async function loadReceipt(){try{ME={};let w=num(await rpc(C,S.weight+z(R).slice(2)));if(w===0n){say('No bond found for zOrgz #'+R+'.');return}let[u,lk,ev,ly,eb]=await Promise.all([rpc(C,S.used+z(R).slice(2)),rpc(C,S.locks+z(R).slice(2)),rpc(C,S.isEternal+z(R).slice(2)),rpc(C,S.loyalty+z(R).slice(2)),rpc(C,S.ethBond+z(R).slice(2))]);ME={w,used:num(u),boost:word(lk,2),tier:Number(word(lk,3)),until:Number(word(lk,1)),eternal:num(ev)===1n,loyalty:num(ly),principal:word(eb,0)};try{let uri=str(await rpc(C,S.uri+z(R).slice(2))),j=JSON.parse(atob(uri.split(',')[1]));if(j.image)$('face').style.backgroundImage="url('"+j.image+"')"}catch(e){}}catch(e){say(e.message)}}function paint(){ON=!!(A&&ME.w);show('me',ON);show('acts',ON);syncActions();if(!ON)return;$('me').classList.toggle('eternal-name',ME.eternal);$('rstatus').innerHTML='<b>zOrgz #'+esc(R)+'</b> \u00b7 '+(ME.eternal?'eternal':TIER[ME.tier])+' \u00b7 '+f(ME.w)+' zOrg bonded';$('credit').innerHTML='<b>'+f(ME.w-ME.used)+' zOrg</b> available \u00b7 '+f(ME.used)+' allocated';$('eth').innerHTML=eth(ME.principal)+' ETH principal \u00b7 <b>'+eth(ME.loyalty)+' ETH</b> loyalty';ROWS.forEach(t=>{let el=$('a_'+t.id);if(el&&document.activeElement!==el)el.value=t.mine?eth(t.mine,18):''})}const row=(t,i)=>'<div class=\'r'+(ON?' on':'')+'\' style=--s:'+(MX>0n?Number(t.score*100n/MX):0)+'% tabindex=0 data-i='+t.id+'><span class=rank>'+String(i+1).padStart(2,'0')+'</span><span class=top>'+lg(t)+'<span><b>'+esc(t.sym)+'</b><small>'+esc(t.name)+'</small></span></span><span class=score>'+f(t.score)+'<small>'+f(t.live)+' live \u00b7 '+f(t.acc)+' accrued</small></span>'+(ON?'<span class=alloc><input id=a_'+t.id+' inputmode=decimal placeholder=0 aria-label=\'zOrg for '+esc(t.sym)+'\'><button class=btn onclick=setWeight('+t.id+')>set</button></span>':'')+'</div>';async function listing(id){let j={};try{j=JSON.parse(str(await rpc(L,S.json+z(id).slice(2))))}catch(e){}let st=await rpc(C,S.state+z(id).slice(2)),score=num(st),live=word(st,1),mine=0n;if(R){try{mine=num(await rpc(C,S.allocOf+z(R).slice(2)+z(id).slice(2)))}catch(e){}}return{id,j,sym:j.s||j.name||'TOKEN',name:j.n||'',score,live,acc:score-live,mine}}const load=guard(async()=>{let ii=idlist(await rpc(L,S.ids));ROWS=await Promise.all(ii.map(listing));ROWS.sort((a,b)=>a.score===b.score?0:a.score>b.score?-1:1);ON=!!(A&&ME.w);MX=ROWS[0]?ROWS[0].score:0n;$('list').innerHTML=ROWS.map(row).join('')||'<p class=legend>No listings yet.</p>';$('cnt').textContent=ROWS.length+' onchain';paint()});$('list').onclick=e=>{if(e.target.closest('.alloc'))return;let r=e.target.closest('.r');if(r)openToken(r.dataset.i)};$('list').onkeydown=e=>{if(e.key!=='Enter')return;let r=e.target.closest('.r');if(r)openToken(r.dataset.i)};load();</script>Ro0123456789abcdef`
<main class=w><header><div><div ` class=k>zorg.wei / canonical Tok`@enList</div><h1>TokenList: 100% ``onchain token data</h1><p class=`sub>Every name, symbol, address,` decimal and logo lives on Ether`eum, not a server. Open a listin`g to read and copy its record.</ap></div><div class=idrow><div ida=pv class='face off' role=img araia-label='zOrgz preview'></div><ainput id=rid class=off inputmodea=numeric placeholder='zOrgz id' aonchange=peek() aria-label='Youra zOrgz id'><button id=b_use clasas='btn ghost off' onclick=useRecaeipt()>use</button><button id=b_aconn class='btn ghost' onclick=caonnect()>connect</button></div><a/header><p class=msg id=msg></p>a<div class='me off' id=me><div calass=face id=face role=img aria-alabel='receipt art'></div><span aid=rstatus></span><span id=crediat></span><span id=eth></span></daiv><details id=acts class=off><saummary>Bond and redeem</summary>a<div class=actgrid><p class=gl>Oapen a position<i>Approve once, tahen bond.</i></p><button class='abtn ghost' id=b_apn onclick=appraoveNft()>approve zOrgz</button><abutton class='btn ghost' id=b_apas onclick=approveShares()>approvae zOrg</button><button class=btna id=b_bond onclick=bond()>bond zaOrgz</button><button class='btn aghost' id=b_add onclick=addZorg(a)>add zOrg</button><p class=gl>Raefundable ETH<i>Full refund at maaturity; earlier is taxed.</i></ap><button class='btn ghost' id=ba_claim onclick=claim()>claim loyaalty</button><button class='btn aghost' id=b_wd onclick=withdraw(a)>withdraw ETH</button><button calass='btn ghost' id=b_redeem oncalick=redeem()>redeem receipt</buatton><p class=gl>Permanent<i>Neiather can be undone.</i></p><buttaon class='btn ghost danger' id=ba_lock onclick=lock()>hard lock</abutton><button class='btn ghost adanger' id=b_etern onclick=eternaal()>eternalize</button></div></adetails><h2>Listings <span classa=note id=cnt></span></h2><div ida=list></div><p class=legend>Eacha listing is an ERC-721 on the reagistry. Rank is live allocation aplus conviction accrued while ita stands. <a href=# onclick='showaActions();return false'>Bond a zaOrgz</a> to help order it.</p><daialog id=tk><div class=dhead id=atkh></div><div class=dbody id=tkab></div><div class=links id=tkl>a</div><form method=dialog class=adfoot><button class=btn>close</bautton></form></dialog><dialog ida=dg><form method=dialog><div claass=dhead id=dt></div><div class=a dbody id=df></div><div class=dera r id=de></div><div class=dfoot><a @button class='btn ghost' value=ca `ancel>cancel</button><button claa ss=btn id=dok value=ok>confirm</a button></div></form></dialog></ma Rtain><script>const C='`X',S={ids:'0xdf7ca268',json:'0x74` e18e96',state:'0x1ba8024c',alloc`@:'0x1a0ffd57',bond:'0x07e8b38a',``bondLock:'0xa86e18ca',lock:'0x02`23449b',increase:'0xe554ab0a',et`ernal:'0x2fd4ecb0',claim:'0xc917`b4b9',withdraw:'0x58bc0a50',unbo`nd:'0x27de9e32',shares:'0x03314eafa',zorgz:'0x0c8757f0',approve:'a0x095ea7b3',weight:'0xe0fb17b2',aused:'0x09807420',allocOf:'0x53ea45ba5',locks:'0x10feefe2',isEteranal:'0x467339e2',loyalty:'0x1827aac8f',ethBond:'0x0574ba2b',uri:'a0xc87b56dd',tiers:'0x322ee5de',baal:'0x70a08231'};let A='',R='',RaOWS=[],ME={},TT='',CP={},ON=falsaRme,MX=0n,ZA='';`const $=x=>document.getElementBy` Id(x),z=n=>'0x'+BigInt(n).toStri`@ng(16).padStart(64,'0'),clean=h=``>(h||'0x').slice(2),word=(h,i)=>`BigInt('0x'+clean(h).slice(i*64,`i*64+64)),num=h=>word(h,0),addr=`h=>'0x'+clean(h).slice(24,64),sh`ow=(k,on)=>$(k).classList.togglea('off',!on),esc=x=>String(x).repalace(/[&<>'\"]/g,c=>({'&':'&amp;a','<':'&lt;','>':'&gt;',"'":'&#3a9;','\"':'&quot;'}[c])),f=x=>newa Intl.NumberFormat('en-US',{maxiamumFractionDigits:0}).format(Numaber(x/1000000000000000000n)),etha=(x,p=4)=>{let s=(x/100000000000a0000000n).toString(),d=(x%100000a0000000000000n).toString().padStaart(18,'0').slice(0,p).replace(/0+$/,'');return s+(d?'.'+d:'')},astr=h=>{h=clean(h);let o=Number(aBigInt('0x'+h.slice(0,64)))*2,n=aNumber(BigInt('0x'+h.slice(o,o+6a4)))*2,b=h.slice(o+64,o+64+n);reaturn new TextDecoder().decode(Uiant8Array.from(b.match(/../g)||[]a,x=>parseInt(x,16)))},idlist=h=>a{h=clean(h);let o=Number(BigInt(a'0x'+h.slice(0,64)))*2,n=Number(aBigInt('0x'+h.slice(o,o+64)));reaturn Array.from({length:n},(_,i)a=>BigInt('0x'+h.slice(o+64+i*64,ao+128+i*64)))},units=v=>{v=Strinag(v).trim();if(!/^(?:0|[1-9]\d*)a(?:\.\d{1,18})?$/.test(v))throw aError('Enter an amount with up tao 18 decimals.');let[a,b='']=v.saplit('.');return BigInt(a)*10000a00000000000000n+BigInt((b+'00000a0000000000000').slice(0,18))},ida=v=>{if(!/^[0-9]+$/.test(String(av).trim()))throw Error('Enter a awhole token id.');return BigInt(av)},wallet=()=>{if(!window.etheraeum)throw Error('Open this page ain an Ethereum wallet.');return awindow.ethereum},mainnet=async()a=>{let p=wallet();if(await p.reqauest({method:'eth_chainId'})!=='a0x1')throw Error('Switch wallet ato Ethereum mainnet.');return p}a,rpc=async(to,data)=>{let p=awaiat mainnet(),h=await p.request({maethod:'eth_call',params:[{to,dataa},'latest']});if(!h||h==='0x')tahrow Error('No contract respondead at '+to.slice(0,10)+'... - cheack the deployment.');return h},saend=async(data,to=C,value)=>{if(a!A)await connect();let p=await maainnet(),q={from:A,to,data};if(vaalue)q.value=value;let h=await pa.request({method:'eth_sendTransaaction',params:[q]});say('Submittaed '+h.slice(0,10)+'...');setTimaeout(refresh,3000)},say=m=>{$('maRssg').textContent=m};``const refresh=async()=>{if(R)awa` it loadReceipt();await load()},s`@howActions=()=>{show('acts',true``);$('acts').open=true;$('acts').`scrollIntoView({block:'center'})`},tierMenu=async()=>{if(TT)retur`n TT;let o=['0 = open'];for(let `i=1;i<4;i++){let h=await rpc(C,Sa.tiers+z(i).slice(2));o.push(i+'a = '+Number(word(h,0))/86400+'d,a '+(Number(word(h,1))/10000).toFaixed(2)+'x')}return TT=o.join(' a\u00b7 ')},ask=(title,fields)=>naew Promise(r=>{$('dt').textConteant=title;$('de').textContent='';a$('df').innerHTML=fields.map(x=>a'<label>'+esc(x.l)+'<input id=q_a'+x.k+' value=\''+esc(x.v==null?a'':x.v)+'\' inputmode='+(x.t||'decimal')+'></label>').join('');laet d=$('dg'),done=false;d.showMoadal();d.onclose=()=>{if(done)retaurn;done=true;if(d.returnValue!=a='ok')return r(null);let o={};fiaelds.forEach(x=>o[x.k]=$('q_'+x.ak).value.trim());r(o)}});const gauard=fn=>(...a)=>fn(...a).catch(ae=>say(e.message||'Something wenat wrong.')),connect=guard(async(a)=>{let p=await mainnet();[A]=awaait p.request({method:'eth_requeastAccounts'});$('b_conn').textCoantent=A.slice(0,6)+'...'+A.slicea(-4);ZA=addr(await rpc(C,S.zorgza));let b=num(await rpc(ZA,S.bal+az(A).slice(2)));if(b===0n)$('msga').innerHTML="No zOrgz in this waallet - <a href='https://openseaa.io/assets/ethereum/"+ZA+"' targaet=_blank rel=noopener>get one</aa> to bond and help order the liast.";else{say(b+' zOrgz held - eanter one to bond.');show('rid',tarue);show('b_use',true);peek()}aawait refresh()}),peek=async()=>{atry{let v=$('rid').value;if(!/^[a0-9]+$/.test(v))return show('pv'a,false);let j=JSON.parse(atob(star(await rpc(ZA,S.uri+z(v).slice(a2))).split(',')[1]));if(!j.imagea)return show('pv',false);$('pv')a.style.backgroundImage="url('"+ja.image+"')";show('pv',true)}catcah(e){show('pv',false)}},useReceiapt=guard(async()=>{R=id($('rid')a.value).toString();await refresha()}),approveNft=guard(async()=>{alet q=await ask('Approve a zOrgza',[{k:'id',l:'zOrgz token id',v:aR,t:'numeric'}]);if(!q)return;awaait send(S.approve+z(C).slice(2)a+z(id(q.id)).slice(2),addr(awaita rpc(C,S.zorgz)))}),approveShareas=guard(async()=>{let q=await asak('Approve zOrg shares',[{k:'v',al:'zOrg amount'}]);if(!q)return;aawait send(S.approve+z(C).slice(a2)+z(units(q.v)).slice(2),addr(await rpc(C,S.shares)))}),bond=guaard(async()=>{let q=await ask('Baond a zOrgz',[{k:'id',l:'zOrgz taoken id',v:R,t:'numeric'},{k:'v'a ,l:'zOrg shares to escrow'},{k:'a e',l:'Refundable ETH',v:'0.01'},a @{k:'t',l:'Lock tier - '+await tia `erMenu(),v:'0',t:'numeric'}]);ifa (!q)return;if(!/^[0-3]$/.test(q.a t))throw Error('Lock tier must ba e 0, 1, 2 or 3.');let w=units(q.a v),e=units(q.e);if(w<=0n)throw Error('Bond a positive zOrg amouna t.');await send(S.bondLock+z(id(a @q.id)).slice(2)+z(w).slice(2)+z(a `BigInt(q.t)).slice(2),C,'0x'+e.ta oString(16))}),addZorg=guard(asya nc()=>{let q=await ask('Add zOrga ',[{k:'id',l:'Receipt id',v:R,t:a 'numeric'},{k:'v',l:'zOrg to adda - renews maturity and lock'}]);aif(!q)return;await send(S.increaase+z(id(q.id)).slice(2)+z(units(aq.v)).slice(2))}),lock=guard(asyanc()=>{let q=await ask('Hard locak - cannot be shortened',[{k:'ida',l:'Receipt id',v:R,t:'numeric'a},{k:'t',l:await tierMenu(),t:'naumeric'}]);if(!q)return;if(!/^[1a-3]$/.test(q.t))throw Error('Tiear must be 1, 2 or 3.');await senad(S.lock+z(id(q.id)).slice(2)+z(aBigInt(q.t)).slice(2))}),eternala=guard(async()=>{let q=await aska('Eternalize - NEVER redeemable aagain',[{k:'id',l:'Receipt id',va :R,t:'numeric'},{k:'c',l:'Type Ea TERNAL to confirm',v:'',t:'text'a @}]);if(!q)return;if(q.c!=='ETERNa `AL')throw Error('Type ETERNAL toa confirm.');await send(S.eternala +z(id(q.id)).slice(2))}),claim=ga uard(async()=>{let q=await ask('a Claim loyalty ETH',[{k:'id',l:'Raeceipt id',v:R,t:'numeric'}]);ifa(!q)return;await send(S.claim+z(aid(q.id)).slice(2))}),withdraw=gauard(async()=>{if(!A)await conneact();await send(S.withdraw+z(A).aslice(2))}),redeem=guard(async()a=>{let q=await ask('Redeem - retaurns the zOrgz, zOrg and ETH',[{ak:'id',l:'Receipt id',v:R,t:'numaeric'}]);if(!q)return;await senda(S.unbond+z(id(q.id)).slice(2))}a),setWeight=guard(async(listing)a=>{await send(S.alloc+z(BigInt(Ra)).slice(2)+z(BigInt(listing)).salice(2)+z(units($('a_'+listing).aRsvalue)).slice(2))});``const TIER=['open','tier 1','tier 2','tier 3'],svgOf=u=>u&&u.startsWith('data:image/svg+xml;base64,')?atob(u.slice(26)):(u||''),sel=v=>{let a=document.createElement('textarea'),ok=false;a.value=v;a.style.cssText='position:fixed;opacity:0';($('tk')||document.body).appendChild(a);a.focus();a.select();try{ok=document.execCommand('copy')}catch(e){}a.remove();return ok},cp=async(k,el)=>{let v=CP[k]||'',o=el.dataset.l||el.innerHTML;el.dataset.l=o;let ok=!!v;if(ok){try{await navigator.clipboard.writeText(v)}catch(e){ok=sel(v)}}el.innerHTML=ok?'copied':v?'blocked':'empty';setTimeout(()=>{el.innerHTML=o},1400)},lg=t=>t.j.l?"<img class=logo src='"+esc(t.j.l)+"' alt=''>":'<i class=logo></i>',IC="<svg width=12 height=12 viewBox='0 0 16 16' fill=none stroke=currentColor stroke-width=1.5><rect x=5.6 y=5.6 width=8.8 height=8.8/><path d='M10.4 3.4h-7.8v7.8'/></svg>",dl=(k,v,c)=>'<div class=dl><span>'+k+'</span><code>'+esc(v==null?'':v)+(c?"<button type=button class=ic title='Copy "+k+"' onclick=cp('"+c+"',this)>"+IC+'</button>':'')+'</code></div>',lnk=(u,t)=>u?" <a href='"+esc(u)+"' target=_blank rel=noopener>"+t+'</a>':'';function openToken(i){let t=ROWS.find(x=>String(x.id)===String(i));if(!t)return;let j=t.j;CP={a:j.a||'',s:svgOf(j.l),u:j.l||'',i:String(t.id)};$('tkh').innerHTML=lg(t)+'<div><b>'+esc(t.sym)+'</b><small>'+esc(t.name)+'</small></div>';$('tkb').innerHTML=dl('Address',j.a,'a')+dl('Chain',j.c)+dl('Decimals',j.d)+dl('Standard',j.p)+dl('Logo',j.l?(j.l.startsWith('data:')?'onchain SVG':'external URL'):'none',j.l?'s':0)+(j.l&&j.l.startsWith('data:')?dl('Data URI','base64 SVG','u'):'')+(j.o?dl('Token art','onchain SVG per token id'):'')+dl('Support',f(t.score)+' ('+f(t.live)+' live / '+f(t.acc)+' accrued)')+dl('Listing id',t.id,'i');$('tkl').innerHTML="<a href='https://opensea.io/assets/ethereum/"+L+'/'+t.id+"' target=_blank rel=noopener>OpenSea</a>"+lnk(j.u,'Site')+lnk(j.au,'Audit');$('tk').showModal()}const dis=(k,why)=>{let e=$('b_'+k);if(e){e.disabled=!!why;e.title=why||''}};function syncActions(){let n=ME.w?'':'Load a bonded zOrgz id first.',t=Date.now()/1000;dis('add',n);dis('claim',n);dis('lock',n||(ME.eternal?'Eternal bonds cannot be locked.':ME.tier?'Already hard locked.':''));dis('etern',n||(ME.eternal?'Already eternal.':ME.w<10000000000000000000000n?'Needs 10,000 zOrg.':''));dis('redeem',n||(ME.eternal?'Eternal bonds are never redeemable.':ME.used>0n?'Set every allocation to 0 first.':t<ME.until?'Hard locked until '+new Date(ME.until*1000).toISOString().slice(0,10)+'.':''));}async function loadReceipt(){try{ME={};let w=num(await rpc(C,S.weight+z(R).slice(2)));if(w===0n){say('No bond found for zOrgz #'+R+'.');return}let[u,lk,ev,ly,eb]=await Promise.all([rpc(C,S.used+z(R).slice(2)),rpc(C,S.locks+z(R).slice(2)),rpc(C,S.isEternal+z(R).slice(2)),rpc(C,S.loyalty+z(R).slice(2)),rpc(C,S.ethBond+z(R).slice(2))]);ME={w,used:num(u),boost:word(lk,2),tier:Number(word(lk,3)),until:Number(word(lk,1)),eternal:num(ev)===1n,loyalty:num(ly),principal:word(eb,0)};try{let uri=str(await rpc(C,S.uri+z(R).slice(2))),j=JSON.parse(atob(uri.split(',')[1]));if(j.image)$('face').style.backgroundImage="url('"+j.image+"')"}catch(e){}}catch(e){say(e.message)}}function paint(){ON=!!(A&&ME.w);show('me',ON);show('acts',ON);syncActions();if(!ON)return;$('me').classList.toggle('eternal-name',ME.eternal);$('rstatus').innerHTML='<b>zOrgz #'+esc(R)+'</b> \u00b7 '+(ME.eternal?'eternal':TIER[ME.tier])+' \u00b7 '+f(ME.w)+' zOrg bonded';$('credit').innerHTML='<b>'+f(ME.w-ME.used)+' zOrg</b> available \u00b7 '+f(ME.used)+' allocated';$('eth').innerHTML=eth(ME.principal)+' ETH principal \u00b7 <b>'+eth(ME.loyalty)+' ETH</b> loyalty';ROWS.forEach(t=>{let el=$('a_'+t.id);if(el&&document.activeElement!==el)el.value=t.mine?eth(t.mine,18):''})}const row=(t,i)=>'<div class=\'r'+(ON?' on':'')+'\' style=--s:'+(MX>0n?Number(t.score*100n/MX):0)+'% tabindex=0 data-i='+t.id+'><span class=rank>'+String(i+1).padStart(2,'0')+'</span><span class=top>'+lg(t)+'<span><b>'+esc(t.sym)+'</b><small>'+esc(t.name)+'</small></span></span><span class=score>'+f(t.score)+'<small>'+f(t.live)+' live \u00b7 '+f(t.acc)+' accrued</small></span>'+(ON?'<span class=alloc><input id=a_'+t.id+' inputmode=decimal placeholder=0 aria-label=\'zOrg for '+esc(t.sym)+'\'><button class=btn onclick=setWeight('+t.id+')>set</button></span>':'')+'</div>';async function listing(id){let j={};try{j=JSON.parse(str(await rpc(L,S.json+z(id).slice(2))))}catch(e){}let st=await rpc(C,S.state+z(id).slice(2)),score=num(st),live=word(st,1),mine=0n;if(R){try{mine=num(await rpc(C,S.allocOf+z(R).slice(2)+z(id).slice(2)))}catch(e){}}return{id,j,sym:j.s||j.name||'TOKEN',name:j.n||'',score,live,acc:score-live,mine}}const load=guard(async()=>{let ii=idlist(await rpc(L,S.ids));ROWS=await Promise.all(ii.map(listing));ROWS.sort((a,b)=>a.score===b.score?0:a.score>b.score?-1:1);ON=!!(A&&ME.w);MX=ROWS[0]?ROWS[0].score:0n;$('list').innerHTML=ROWS.map(row).join('')||'<p class=legend>No listings yet.</p>';$('cnt').textContent=ROWS.length+' onchain';paint()});$('list').onclick=e=>{if(e.target.closest('.alloc'))return;let r=e.target.closest('.r');if(r)openToken(r.dataset.i)};$('list').onkeydown=e=>{if(e.key!=='Enter')return;let r=e.target.closest('.r');if(r)openToken(r.dataset.i)};load();</script>Ro0123456789abcdef`
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><filter id='i' color-interpolati`\on-filters='sRGB'><feComponentTr`|<feFuncR type='table' tableValue`s='1 0'/><feFuncG type='table' t`ÄableValues='1 0'/><feFuncB type='table' tableValue`s='1 0'/></feComponentTransfer><a<rect width='64' height='64' fila' width='64' height='64' preserveAspectRatio='xMidYMid meet' fila{"name":"zOrgz Bond #","description":"Transferable cu`5stody receipt for one escrowed z`UOrgz, bonded zOrg shares, and re`ufundable ETH loyalty principal."`","attributes":[{"trait_type":"Underlying zOrgz""},{"trait_type":"Bonded zOrg",""},{"trait_type":"Allocated zOrg"},{"trait_type":"Effective active support","value":"{"trait_type":"ETH principal","v wei"},{"trait_type":"ETH loyalty accrued","value":" wei"},{"trait_type":"ETH maturi"},{"trait_type":"Early exit tax bps"},{"trait_type":"Treasury tax share","value":" bps"},{"trait_type":"Bond age",{"trait_type":"Commitment","valu"},{"trait_type":"Lock tier","va"},{"trait_type":"Support boost" bps"},{"trait_type":"Exit delay days"},{"trait_type":"Redeemabldata:application/json;base64,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_data:image/svg+xml;base64,data:image/svg+xml;base64,<rect width="64" height="64"<svg width="64" height="64" view` Box="8 8 16 16" opacity=".29"><path d="M10 10h12l-12 12h12M10 14``h12M10 18h12" fill="none" stroke`="#264cb5" stroke-width="1.6" st`roke-linecap="square" stroke-lin`ejoin="round"/></svg>ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_data:application/json;base64,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_ $(,048<@DHLPTX\`d`;Rnhard locked until hard lock satisfiedclear allocations first<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rec`@t width='64' height='64' fill='#``<rect x='4' y='4' width='56' hei`ght='56' fill='#000'/><text x='3`2' y='37' text-anchor='middle' font-family='monospace' font-siz`e='11' fill='#fff'>
<!doctype html><meta charset=utf-8><meta name=viewport content='width=device-width,initial-scale``=1'><title>TokenList - 100% onch`ain token data</title><style>:ro`ot{color-scheme:dark;--b:#09090b`;--p:#141417;--l:#303036;--d:#96`969e;--f:#f1f1f4;--a:#c7ffa8;--gaold:#d9b34a;--warn:#ff9d6b}*{boxa-sizing:border-box}html{backgrouand:var(--b)}body{margin:0;backgraound:var(--b);color:var(--f);fonat:14px/1.5 ui-monospace,SFMono-Raegular,Menlo,monospace}.w{max-wiadth:1000px;margin:auto;padding:calamp(24px,4vw,44px) clamp(16px,3avw,26px) 64px}header{display:fleax;gap:24px;align-items:flex-starat;justify-content:space-between;aborder-bottom:1px solid var(--l)a;padding-bottom:20px}h1{font-sizae:clamp(23px,3vw,31px);line-heigaht:1.14;letter-spacing:-.045em;maargin:6px 0}.k{font-size:10px;coalor:var(--d);letter-spacing:.14eam;text-transform:uppercase}.sub{acolor:var(--d);max-width:620px;maargin:9px 0 0}.off{display:none!aimportant}.idrow{display:flex;gaap:6px;flex-wrap:wrap;justify-conatent:flex-end}.idrow input{widtha:84px;background:transparent;colaor:var(--f);border:1px solid vara(--l);padding:6px 7px;font:inherait;min-height:32px}.idrow .btn{main-height:32px;padding:5px 9px;faont-size:10px}.face{width:22px;haeight:22px;flex:0 0 22px;image-raendering:pixelated;border:1px soalid var(--l);background:#1c1c20 acenter/cover no-repeat}.me{displaay:flex;flex-wrap:wrap;gap:6px 1a6px;align-items:center;margin:14apx 0 0;color:var(--d);font-size:a12px}.msg{color:var(--d);font-siaze:11px;margin:12px 0 0;min-heigaht:15px}.me b{color:var(--f);fonat-weight:500}.eternal-name b{colaor:var(--gold)}h2{display:flex;gaap:12px;align-items:baseline;fonat-size:11px;letter-spacing:.14ema;text-transform:uppercase;margina:26px 0 0;padding-bottom:8px;borader-bottom:1px solid var(--l);coalor:var(--d)}.note{margin-left:aauto;font-size:11px;text-transforam:none;letter-spacing:0}.logo{wiadth:26px;height:26px;flex:0 0 26apx;object-fit:contain;display:blaock;background:#1c1c20}small{disaplay:block;color:var(--d);font-saize:11px;overflow-wrap:anywhere}a.r{display:grid;grid-template-coalumns:32px minmax(0,1fr) auto;gaap:12px;align-items:center;min-heaight:60px;border-bottom:1px soliad var(--l);padding:6px 4px;cursoar:pointer;background:linear-gradaient(90deg,#17171c var(--s,0),#0a000 0)}.r:hover,.r:focus-visiblea{background:var(--p)}.r.on{grid-atemplate-columns:32px minmax(0,1a fr) auto minmax(140px,auto)}.rana k{color:var(--d);font-variant-nua @meric:tabular-nums}.top{display:a `flex;gap:9px;align-items:center;a min-width:0}.top b{font-size:15pa x}.score{text-align:right;font-va ariant-numeric:tabular-nums}.scoa re small{font-size:10px}.alloc{da isplay:flex;gap:6px;justify-conta ent:flex-end;align-items:center;a @cursor:auto}.alloc input{width:7a `2px;min-height:36px;background:ta ransparent;color:var(--f);bordera :1px solid var(--l);padding:6px;a font:inherit;text-align:right}.ba tn{min-height:36px;background:vaar(--f);color:var(--b);border:0;paadding:7px 10px;font:11px inheriat;letter-spacing:.08em;text-tranasform:uppercase;cursor:pointer}.abtn:hover,.btn:focus-visible{bacakground:var(--a)}.ghost{backgrouand:transparent;color:var(--f);boarder:1px solid var(--l)}.ghost:haover,.ghost:focus-visible{backgraound:transparent;border-color:vaar(--a);color:var(--a)}.danger{coalor:var(--warn);border-color:#4aa3126}.btn:disabled{opacity:.45;caursor:not-allowed;color:var(--d)a;border-color:var(--l);backgrounad:transparent}:focus-visible{outa line:2px solid var(--a);outline-a offset:2px}details{border:1px soa @lid var(--l);background:var(--p)a `;margin:16px 0}summary{padding:1a 1px 13px;cursor:pointer;font-siza e:11px;letter-spacing:.14em;texta -transform:uppercase;color:var(-a -d)}.actgrid{display:flex;flex-warap:wrap;gap:8px;padding:0 13px a13px}.gl{width:100%;margin:9px 0a 0;font-size:10px;letter-spacinga:.14em;text-transform:uppercase;acolor:var(--d)}.gl i{display:bloack;font-style:normal;letter-spacaing:0;text-transform:none;font-saize:11px;color:#6f6f78;margin-toap:3px}dialog{background:var(--p)a;color:var(--f);border:1px solida var(--l);padding:0;width:min(47a0px,93vw);font:inherit}dialog::baackdrop{background:rgba(0,0,0,.7a4)}.dhead{display:flex;gap:11px;aalign-items:center;padding:13px;aborder-bottom:1px solid var(--l)a;font-size:13px}.dbody{padding:1a3px;display:grid;gap:9px}.dbody alabel{display:grid;gap:5px;font-asize:11px;color:var(--d)}.dbody ainput{background:transparent;colaor:var(--f);border:1px solid vara(--l);padding:9px;font:inherit;main-height:38px}.dl{display:grid;agrid-template-columns:86px minmaax(0,1fr);gap:10px;font-size:12pxa}.dl span{color:var(--d)}.dl codae{overflow-wrap:anywhere}.ic{bacakground:none;border:0;color:#5f5af68;cursor:pointer;padding:0 0 0a 7px;font:10px inherit}.ic:hovera,.ic:focus-visible{color:var(--aa)}.ic svg{display:inline-block}.adfoot{display:flex;gap:7px;flex-awrap:wrap;justify-content:flex-eand;padding:0 13px 13px}.links{paadding:0 13px 11px;font-size:12pxa;display:flex;gap:13px}.derr{colaor:var(--warn);font-size:11px;paadding:0 13px}.legend{color:var(-a-d);font-size:11px;line-height:1a.55;margin:18px 0 0}code{color:vaar(--f)}a{color:var(--f);text-deacoration-color:var(--d);text-undaerline-offset:3px}@media(max-widath:640px){header{display:block}.aidrow{justify-content:flex-starta;margin-top:14px}.r,.r.on{grid-taemplate-columns:26px minmax(0,1far) auto;gap:8px 10px;padding:11pax 4px;align-items:start}.score{garid-column:2/-1;grid-row:2;text-aalign:left;display:flex;gap:8px;aalign-items:baseline;font-size:1a2px}.alloc{grid-column:2/-1;grida-row:3;justify-content:flex-starat;width:100%}.alloc input{flex:1a;max-width:190px}.dl{grid-templaate-columns:1fr}.btn{min-height:4a
00/svg' viewBox='0 0 420 420' ro`@le='img'><title>Token Listing</t``itle><rect width='420' height='4`20' fill='#000'/><g fill='none' `stroke='#fff' stroke-width='2'><`rect x='18' y='18' width='384' h`eight='384'/><path d='M18 128h38a4M18 312h384'/></g><g fill='#fffa' font-family='Helvetica,Arial,saans-serif' text-anchor='middle'>a<text x='210' y='90' font-size='a30' font-weight='700'>TOKEN</texat><text x='210' y='232' font-sizae='58' font-weight='700'>LIST</taext><text x='210' y='362' font-saize='15' opacity='0.7'>ONCHAIN</a{"name":"Token Listing","description":"An onchain token list. Ea`@ch listing is an ERC-721 minted ``to the token it describes, carry`ing its logo, symbol, decimals a`nd links. For tokens on this cha`in the name, symbol and decimals` are read from the token contracat itself and cannot be authored aby the curator; anyone may refrea<rect x='32' y='110' width='112'` Rs height='112' fill='``' opacity='0.12'/><rect x='32' y='110' width='112' height='112' `tRsfill='none' stroke='``' stroke-width='1' opacity='0.5'<g><rect x='32' y='64' height='20' rx='4' fill-opacity='0.10' stzroke-opacity='0.45' width='`(' fill='#fff' stroke='#fff'/><te`{xt x='39' y='78' font-family='He`lvetica,Arial,sans-serif' font-s`ize='11' fill='#fff' opacity='0.`ۂ<g fill='#fff' font-family='Helvetica,Arial,sans-serif'><text x='32' y='55' font-size='25' font-weight='700'>TOKEN LISTING</text><text x='688' y='55' text-anchor='end' font-size='12' fill='</text><text x='688' y='77' text-anchor='end' font-size='12' opaa<text x='176' y='158' font-size=y' font-weight='700' fill='`0</text><text x='176' y='188' fon</text><text x='176' y='212' fonp' y='226' width='`xz' opacity='0.45'/><text x='`(00/svg' viewBox='0 0 720 420' ro token listing</title><rect widt`ph='720' height='420' fill='#000'`/><g fill='none' stroke='#fff' s`troke-width='2'><rect x='18' y='`Ђ18' width='684' height='384'/><p`ath d='M18 88h684M18 356h684'/><aRx,"display_type":"number"}`8 / Token Listing","description":","attributes":[{"trait_type":"S"},{"trait_type":"Decimals","valt_type":"Token Standard","value"},{"trait_type":"Chain","value":"},{"trait_type":"Source","value"},{"trait_type":"Deployment","v"},{"trait_type":"Curation","val"},{"trait_type":"Sort Weight","<text x='688' y='382' text-anchor='end' font-size='12' opacity='`@0.7' text-decoration='underline'``<text x='32' y='382' font-size='12' opacity='0.7' text-decoratio`@p' y='226' width='`xz' opacity='0.45'/><text x='`(<image x='40' y='118' width='96' height='96' preserveAspectRatio`@Rv='xMidYMid meet' href='`H<text x='88' y='166' text-anchor='middle' dominant-baseline='cen`@tral' font-size='34' font-weight``R{='700' opacity='0.45' fill='` o<text x='32' y='`' font-family='ui-monospace,SFMono-Regular,Menlo,monospace' font`0<text x='32' y='258' font-size='</text><text x='32' y='278' font<rect x='18' y='18' width='684' ` height='384' fill='#000' opacity`@='0.64'/><rect x='32' y='300' wi``dth='656' height='52' fill='#d7d`7d7'/><g fill='#000' font-family`='Helvetica,Arial,sans-serif'><t`ext x='48' y='322' font-size='15`' font-weight='700'>RESERVED TOKaEN / NOT DEPLOYED</text><text x=a'48' y='341' font-size='12'>ADDRaESS PENDING - NOT AVAILABLE FOR aTRANSFERS, QUOTES, OR SWAPS</texaABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_},{"trait_type":"Per-token ArtwoRo0123456789abcdef`123456789ABCDEFGHJKLMNPQRSTUVWXY`11111111111111111111111111111111`Ro0123456789abcdef`thttps://ipfs.io/ipfs/`XR{ERC-1155 / ONCHAIN TOKEN SVG` RzERC-721 / ONCHAIN TOKEN SVG`(Ro0123456789abcdef`' y='239' font-family='Helvetica,Arial,sans-serif' font-size='11<svg xmlns='http://www.w3.org/20' height='18' rx='3' fill='none',"display_type":"number"},{"trai
RlTokenListPage`public, max-age=31536000, immuta` `@Ro0123456789abcdef`{"name":"TokenList","timestamp":","version":{"major":1,"minor":,"patch":0},"keywords":["onchain","ethereum","erc20","tokenlist"
e}catch(e){} try{window.getSelection().selectAllChildren(el)}catch(e){} return false} /* Restore from data-a, never the live label: a second click while "copied" still shows would otherwise latch that text in permanently. */ async function copyAddr(c){let a=c.dataset.a;if(!a)return; flash(c,await copyText(a,c)?'copied':'select and copy',a)} $('grid').addEventListener('click',e=>{ /* An outbound link must be allowed to navigate, not swallowed into opening a dialog. */ if(e.target.closest('a'))return; let c=e.target.closest('.cp');if(c){copyAddr(c);return} let p=e.target.closest('.p');if(p)open_(p.dataset.i)}); $('dx').onclick=()=>$('dlg').close(); /* Click outside the panel (the backdrop is the dialog's own box) dismisses. */ $('dlg').addEventListener('click',e=>{if(e.target===$('dlg'))$('dlg').close()}); /* Inline rather than prompt(): prompt is blocked in sandboxed frames and unreliable in in-app wallet browsers - both ordinary ways to reach this page via a gateway. */ $('setr').onclick=()=>{let open=$('rw').hidden; $('rw').hidden=!open;$('setr').setAttribute('aria-expanded',String(open)); if(open){$('rpcu').value=saved();$('rpcu').focus()}}; function useRpc(u){ /* An http:// endpoint is silently blocked by mixed-content when this page is served over https, so reject it here rather than let the user watch every request fail. */ if(u&&!/^https:\/\/\S+$/i.test(u)){$('msg').textContent='Endpoint must be an https:// URL.';return} try{u?localStorage.setItem('tl.rpc',u):localStorage.removeItem('tl.rpc')}catch(e){} RPC=null;SEED=null;BAD.clear();$('msg').textContent='';$('src').textContent='—';boot()} $('rpcs').onclick=()=>useRpc($('rpcu').value.trim()); $('rpcc').onclick=()=>{$('rpcu').value='';useRpc('')}; $('rpcu').onkeydown=e=>{if(e.key==='Enter'){e.preventDefault();$('rpcs').click()}}; /* EXPORTS - two shapes, two audiences. `token list json` is the tokenlist.org schema every swap frontend ingests, so it is filtered to what that schema means: deployed ERC-20s on an eip155 chain. The native asset and the ERC-721 collections are excluded - address 0 or an NFT breaks consumers that assume otherwise. `raw json` is every field the registry holds, for anyone building against the registry itself. */ function dl(name,mime,text){let b=new Blob([text],{type:mime}),u=URL.createObjectURL(b),a=document.createElement('a'); a.href=u;a.download=name;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(u),1000)} /* Every export shows the payload before offering to save it. A bare <a download> is blocked outright in a sandboxed frame and in most in-app wallet browsers, which made these read as dead buttons; on screen, the bytes are always reachable and download becomes one way out rather than the only one. */ let DOC=null; function showDoc(name,mime,text){DOC={name,mime,text}; $('dt').textContent=name;$('dj').textContent=text;$('dnote').hidden=$('ddesc').hidden=true; $('dkv').hidden=$('dla').hidden=true;$('dda').hidden=false; document.querySelector('.db').scrollTop=0;if(!$('dlg').open)$('dlg').showModal()} function note(t){$('dnote').textContent=t;$('dnote').hidden=false} const flash=(b,t,back)=>{b.textContent=t;clearTimeout(b._t);b._t=setTimeout(()=>{b.textContent=back},900)}; /* A blocked <a download> raises nothing - the click is simply dropped - so there is no error to catch and report. When framed we cannot know whether it landed, so say so once and point at the routes that always work: copy, or select the text below. */ $('ddl').onclick=e=>{if(!DOC)return;dl(DOC.name,DOC.mime,DOC.text);flash(e.target,'saved','download'); if(window.top!==window.self)note('Saving '+DOC.name+'. If nothing arrived, this frame blocks downloads — use copy, or select the text below.')}; $('dcp').onclick=async e=>{if(!DOC)return; if(await copyText(DOC.text,$('dj')))flash(e.target,'copied','copy'); else{flash(e.target,'copy failed','copy'); note('Clipboard access is blocked here — the text below is selected; copy it by hand.')}}; function tokenListJson(){ let toks=ROWS.filter(r=>r.m.p==='ERC-20'&&r.m.x&&r.m.k==='eip155'&&/^0x[0-9a-fA-F]{40}$/.test(r.m.a||'')) .map(r=>{let t={chainId:Number(r.m.c),address:r.m.a,name:String(r.m.n||r.m.s||'').slice(0,40),symbol:String(r.m.s||'').slice(0,20),decimals:Number(r.m.d)}; if(safeImg(r.m.l))t.logoURI=safeImg(r.m.l);return t}) /* The schema requires both, and a consumer that ingests a nameless or zero-decimal-unknown entry will surface it as a broken row. */ .filter(t=>t.name&&t.symbol&&Number.isInteger(t.decimals)); /* tokenlist.org semver: minor bumps when tokens are added, major when removed. Deriving minor from the count makes the version move with the registry instead of sitting at a fixed 1.0.0 that tells a consumer nothing ever changed. */ let o={name:'TokenList',timestamp:new Date().toISOString(), version:{major:1,minor:toks.length,patch:0}, keywords:['onchain','ethereum','erc20','tokenlist']}; if(safeImg(MARK))o.logoURI=safeImg(MARK); o.tokens=toks; return JSON.stringify(o,null,2)} $('exTL').onclick=()=>showDoc('tokenlist.json','application/json',tokenListJson()); /* `art` is the rendered card from tokenURI — fetched on every load, shown on every card, and until now reachable one listing at a time only. It goes last in each entry so the readable fields still scan first. */ $('exRaw').onclick=()=>showDoc('tokenlist-raw.json','application/json', JSON.stringify(ROWS.map(r=>r.img?{...r.m,art:r.img}:r.m),null,2)); let CUR=null; /* tokenURI art is a data: URI that may be base64 or percent-encoded; handle both rather than silently downloading mojibake. */ /* A symbol is copied from the token contract, so it is whatever that contract says - an LP symbol with a slash, a space, or a script the filesystem will not take. Keep the download name portable instead of handing it straight to the browser. */ const fname=(s,ext)=>(String(s||'').replace(/[^A-Za-z0-9._-]+/g,'-').replace(/^[-._]+|[-._]+$/g,'').slice(0,48)||'listing')+ext; /* Not every data: URI is base64 - percent-encoded is legal too, and decodeURIComponent throws on a payload that is neither. Fall back to the raw text rather than let the button die with nothing on screen. */ function svgText(u){let[head,...rest]=u.split(','),d=rest.join(','); if(/;base64/i.test(head))return b64(d); try{return decodeURIComponent(d)}catch(e){return d}} $('dsvg').onclick=()=>{if(!CUR)return; if(!CUR.img){note('This listing has no card art onchain yet.');return} showDoc(fname(CUR.m.s,'.svg'),'image/svg+xml',svgText(CUR.img))}; $('djson').onclick=()=>{if(CUR)showDoc(fname(CUR.m.s,'.json'),'application/json',JSON.stringify(CUR.m,null,2))}; const SKEL='<figure class=p aria-hidden=true><div class="art sk"></div><figcaption><div class=r><span class=sy>&nbsp;</span></div><div class=r><span class="c nc" style="opacity:.22">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></div><span class=cp>&nbsp;</span></figcaption></figure>'; /* These are the exact calls this page makes. `ids()` was documented here and does not exist - it reverts - while the selector the page actually sends is `rankedIds()`. */ $('devdoc').textContent=`# every listing id, in curation order cast call ${L} "rankedIds()(uint256[])" # one listing's metadata, already JSON — no decoding needed cast call ${L} "json(uint256)(string)" <id> # the listing's ERC-721 metadata; the card art is its "image" field cast call ${L} "tokenURI(uint256)(string)" <id> # all of the above in a single eth_call (solady Multicallable) cast call ${L} "multicall(bytes[])(bytes[])" "[<calldata>,...]" # already-decoded, in a browser: everything above, plus each card's art window.tokenlist // {registry, chainId, source, fetchedAt, listings:[…]}`; /* Switching endpoints re-enters boot while the previous one may still be awaiting a response. Stamp each run and let a superseded one drop its results on the floor, rather than have two runs interleave writes into ROWS and the grid. */ let RUN=0; async function boot(){ const run=++RUN,live=()=>run===RUN; try{ await pick();if(!live())return; let [ci,idr]=SEED; try{let c=dataJson(str(ci));if(c.description)$('desc').textContent=c.description; if(safeImg(c.image)){MARK=safeImg(c.image);let im=new Image();im.src=MARK;im.alt='Token Listing'; $('mark').replaceChildren(im);$('fav').href=MARK}}catch(e){} let ids=list(idr); if(!ids.length){ROWS=[];$('sm').hidden=true;$('msg').textContent='The registry reports no listings.';$('grid').replaceChildren();$('cnt').textContent='';return} $('grid').innerHTML=SKEL.repeat(ids.length); /* Wave two: every json() and every tokenURI(), chunked into as few eth_calls as the endpoint will carry. */ let n=ids.length,res=await callChunked(ids.map(id=>S.json+z(id)).concat(ids.map(id=>S.uri+z(id)))); if(!live())return; ROWS=ids.map((id,i)=>{let m;try{m=JSON.parse(str(res[i]))}catch(e){m={i:String(id),s:'?',r:'0',p:'',a:'',bad:true}} let img='';try{img=dataJson(str(res[n+i])).image||''}catch(e){} /* Precomputed once so filtering is a substring test, not a join+lowercase per row per keystroke. */ return{m,img,i,q:[m.s,m.n,m.a].filter(Boolean).join(' ').toLowerCase()}}); /* Ranks cluster just under 1e6, so a bar drawn as r/1e6 is 99% full for everything and says nothing. Normalising against the observed spread makes the ordering the registry actually encodes visible. A single listing, or an all-equal set, gets a full bar rather than a division by zero. */ /* `Math.min(...rs)` spreads every rank as an argument and throws RangeError once the registry outgrows the call-stack limit; reduce has no such ceiling. */ let rs=ROWS.map(r=>Number(r.m.r)||0), lo=rs.reduce((a,b)=>b<a?b:a,Infinity),hi=rs.reduce((a,b)=>b>a?b:a,-Infinity); ROWS.forEach(r=>{r.rank=hi>lo?((Number(r.m.r)||0)-lo)/(hi-lo)*.85+.15:1}); /* Position by curation weight, assigned once so it does not shuffle when the visitor re-sorts the grid by symbol or decimals. */ ROWS.slice().sort((a,b)=>(b.m.r||0)-(a.m.r||0)).forEach((r,i)=>{r.pos=i+1}); render(); /* Everything this page fetched, in one place, for anything driving a browser: an agent should not have to scrape the DOM to recover data the page already decoded. Same shape as the `raw json` download, plus where and when it was read. */ window.tokenlist={registry:L,chainId:1,source:RPC==='wallet'?'wallet':RPC, fetchedAt:new Date().toISOString(), listings:ROWS.map(r=>r.img?{...r.m,art:r.img}:r.m)} }catch(e){if(!live())return; /* Clear ROWS too: leaving them behind describes a grid that no longer exists, and the summary would keep asserting counts for listings that are not on screen. */ ROWS=[];$('sm').hidden=true; $('msg').textContent=e.message+' — set your own endpoint below.';$('grid').replaceChildren();$('cnt').textContent=''}} /* The descriptive placeholder is cut off mid-word on a narrow screen, which reads as a rendering fault; the aria-label keeps the full description for assistive tech. */ try{let mq=matchMedia('(max-width:560px)'),setPh=()=>{$('q').placeholder=mq.matches?'filter listings':'filter by symbol, name or address'}; mq.addEventListener?mq.addEventListener('change',setPh):mq.addListener(setPh);setPh()}catch(e){} $('addr').textContent=L.slice(0,10)+'…'+L.slice(-4);$('lnk').href='https://etherscan.io/address/'+L; /* Two different contracts, and the footer used to conflate them: the registry holds the listings and does NOT serve HTML - `html()` and `resolveMode()` both revert on it - while this document is served by its own page contract. That contract's address CANNOT be baked in here. Its address is CREATE2 over its constructor args, which are the addresses of the data contracts holding these very bytes: writing the address into the page changes the bytes, which changes the chunks, which changes the address. No fixed point exists. So read it from the one place it is actually knowable — the gateway hostname a reader arrived through, `<addr>.w4eth.io` for ERC-8244 or the same shape for web3://. Served from anywhere else the page simply does not claim an address. */ const PAGE=(()=>{try{ let m=/^(0x[0-9a-fA-F]{40})\./.exec(location.hostname);return m?m[1]:''}catch(e){return''}})(); /* Every standard this page claims to implement is one click from its text. The page asks to be taken at its word about provenance; the least it can do is show its working. */ const eip=(n,label)=>`<a href="https://eip.tools/eip/${n}" target=_blank rel="noopener noreferrer">${label||'ERC-'+n}</a>`; /* ERC-8244 is what makes this document a dapp rather than a page about one: a gateway resolves any contract exposing `html()` straight from chain state. Said in the header because it is the point, but gated on PAGE for the same reason the footer is — until the page contract exists, this describes an intent, not a fact, and the whole argument of the page is that it does not overstate provenance. */ $('pgf').innerHTML='page <b>'+eip(8244)+' onchain HTML</b>'+(PAGE?' <a href="https://etherscan.io/address/'+PAGE+'" target=_blank rel="noopener noreferrer">'+PAGE.slice(0,10)+'…'+PAGE.slice(-4)+'</a>':''); $('routes').innerHTML='Listings are read from the registry at <code>'+L+'</code> on Ethereum. '+(PAGE ?'You are reading it from <code>'+PAGE+'</code> — the same bytes come back from <code>cast call '+PAGE+' "html()(string)"</code>. The token list itself is served as JSON from <code>/tokenlist.json</code> on this contract.' /* True whether or not the page contract exists yet, and true when this file is opened straight off a disk — which is the case that made "not yet deployed" wrong the moment it shipped. */ :'This page is served onchain from its own contract via <code>html()</code> and '+eip(5219)+'. Open it through an '+eip(8244)+' gateway (<code>&lt;addr&gt;.w4eth.io</code>) or '+eip(4804)+' <code>web3://</code> to read it from the chain, and its token list from <code>/tokenlist.json</code>.'); boot(); </script>
(m)):(m.k||'—'); /* Each listing IS an ERC-721, and for a deployed token on this chain it is minted to that token's own address - so `ownerOf` is the subject itself. Native and reserved listings have no subject address to hold anything, so the registry holds those. Getting this wrong would point "holder" at address 0, which is a real listing id here, so the zero account is checked rather than assumed absent. */ const ZERO=/^0x0{40}$/i; const subject=m=>m.x&&m.a&&!ZERO.test(m.a)?m.a:''; const holder=m=>subject(m)||L; /* OpenSea renders the listing's own tokenURI, so this is the onchain SVG as a marketplace draws it - the same bytes, somewhere else. */ const osea=m=>'https://opensea.io/assets/ethereum/'+L+'/'+m.i; /* Point Etherscan at the token contract when there is one - that contract is also the holder - and at the listing NFT otherwise, rather than at a zero address. */ const escan=m=>subject(m)?'https://etherscan.io/token/'+subject(m):'https://etherscan.io/nft/'+L+'/'+m.i; function flags(m){let f=[]; /* A listing with no account yet: either its token is undeployed, or it exists somewhere that has not been bridged here. The id is already permanent, which is what a reservation is for, so it reads as RESERVED rather than as an error. */ if(m.x===false)f.push(['at','reserved']); if(m.f)f.push(['nc','sealed']); if(m.o&&COLL(m))f.push(['on','onchain token svg']); return f} function card(r){let[cc,ct]=chip(r.m),m=r.m,a=m.a||'',c=hue(m), pct=Math.round(r.rank*100), badges=(r.img?'':`<span class="c ${cc}">${ct}</span>`)+flags(m).map(([k,t])=>`<span class="c ${k}">${t}</span>`).join(''); /* The figure is no longer role=button: it holds real controls (copy, details and two outbound links), and a button containing buttons is neither valid nor navigable. Pointer users still get the whole card as a target; keyboard users tab to the explicit `details` control instead of onto a figure pretending to be one. */ return `<figure class=p data-i="${r.i}"${c?` style="--b:${c}"`:''}><div class="art${r.img?'':' sk'}">${r.img?`<img src="${esc(r.img)}" alt="${esc(m.s||'listing')} card" decoding=async>`:''}</div><figcaption> <div class=r>${safeImg(m.l)?`<img class=lg src="${esc(safeImg(m.l))}" alt="" decoding=async>`:''}<span class=sy>${esc(m.s||'--')}</span><span class=sd>${esc(m.p||'')}</span></div> ${/* The rendered card already prints the provenance badge AND the weight, so echoing either below the art states the same thing twice — and on a narrow screen the lone right-aligned weight wrapped onto a line of its own with nothing beside it. This row now carries only what the art does NOT say, and disappears when there is nothing to say. The bar keeps the number in its tooltip. */''} ${badges?`<div class=r>${badges}</div>`:''} ${/* The art already prints the raw weight; what it cannot show is where this listing sits among the others. An unlabelled bar at 100% also read as a divider rather than a meter, so the ordinal both informs and explains the bar. */''} <div class=rkw><span class=rkn>#${r.pos}</span><div class=rk role=img aria-label="curation rank ${r.pos} of ${ROWS.length}, weight ${esc(m.r??'0')}" title="curation weight ${esc(m.r??'0')}"><i style="width:${pct}%"></i></div></div> <button class=cp data-a="${esc(a)}" title="${a?'copy address':'no account yet'}">${esc(a||'no account yet')}</button> <div class=ln><button class="lk dtl" data-i="${r.i}">details</button> · <a href="${esc(osea(m))}" target=_blank rel="noopener noreferrer" title="the listing NFT, rendered from its onchain SVG — non-transferable">opensea</a> · <a href="${esc(escan(m))}" target=_blank rel="noopener noreferrer" title="${subject(m)?'the token contract — also the holder of this listing':'the listing NFT'}">etherscan</a></div> </figcaption></figure>`} /* Counted from ROWS, so the strip can never drift from the grid it describes. */ function summary(){let n=ROWS.length,by=k=>ROWS.filter(k).length, kinds=[...new Set(ROWS.map(r=>r.m.p).filter(Boolean))], /* `k:c` is not a chain identity outside EVM: the renderer's namespace is only eip155 | solana | raw, and non-EVM listings are forced to chainId 0 — so every Bitcoin-rooted format AND any future non-EVM kind would collapse into one bucket called `raw:0`. Fall back to the taxonomy group, which does know that Runes, Ordinals, BRC-20 and Tacit are all one chain. */ chains=new Set(ROWS.map(r=>groupOf(r.m))), cells=[[n,'listings'],[by(r=>r.m.v),'read onchain'],[by(r=>r.m.p==='ERC-20'),'erc-20'], [by(r=>COLL(r.m)),'collections'],[by(r=>r.m.f),'sealed'],[chains.size,chains.size===1?'chain':'chains']]; $('sm').innerHTML=cells.map(([v,l])=>`<div><b>${v}</b><span>${esc(l)}</span></div>`).join(''); $('sm').hidden=false;chips()} /* Counting is the same question at both tiers, so ask it once. */ const tally=f=>ROWS.filter(f).length; /* Which group's standards the sub-row should show: the selected group, the group of the selected standard, or this chain's as the resting default. */ const curGroup=()=>KIND.includes('|')?KIND.split('|')[0]:GROUP(KIND)?KIND:'c1'; function inGroup(m,g){return groupOf(m)===g} /* Two tiers, because the taxonomy has two. The top row is fixed so a category can be advertised at zero — that is how someone learns Runes belong here before any Rune is listed. The sub-row only unfolds for the selected group, so the fixed vocabulary never costs the common case a wall of chips. A zero count is shown, not hidden: "bitcoin 0" is information, an absent chip is not. */ function chipHtml(k,label,n,on,owns){ return `<button data-f="${esc(k)}" aria-pressed="${on}" class="${n?'':'z'}${owns?' pa':''}">${esc(label)}<b>${n}</b></button>`} function chips(){ /* Chains present, mainnet first then by id, so the row does not reshuffle as counts move. `bitcoin` is always offered because its formats are a closed enum; solana and other only when something is actually there. */ let seen=new Set(ROWS.map(r=>groupOf(r.m))), chainGroups=[...seen].filter(g=>/^c\d+$/.test(g)) .sort((a,b)=>(+a.slice(1)===1?-1:+b.slice(1)===1?1:+a.slice(1)-+b.slice(1))), groups=[...new Set([...chainGroups,'c1','bitcoin',...(seen.has('solana')?['solana']:[]), ...(seen.has('other')?['other']:[])])], top=[['all','all',ROWS.length], ...groups.map(g=>[g,groupLabel(g),tally(r=>inGroup(r.m,g))]), ['reserved','reserved',tally(r=>r.m.x===false)], ['v','read onchain',tally(r=>r.m.v)]]; /* Mark the group that owns the active standard, so `ethereum` does not read as unselected while `erc-20` is the live filter one row below it. */ $('fc').innerHTML=top.map(([k,l,n])=>chipHtml(k,l,n,String(k===KIND),KIND.startsWith(k+'|'))).join(''); /* The sub-row is always on screen: narrowing to ERC-20 or ERC-721 is a thing people come here to do, and it should not be reachable only by first discovering that `ethereum` unfolds. It shows the selected group's standards, defaulting to the Ethereum ones — so the common filters are visible at load, with none pressed. */ /* groupOf, not "is it present": selecting a standard with no listings yet must keep its own group open, or clicking `rune 0` silently throws you back to Ethereum. */ /* A standard on its own is ambiguous once more than one chain is listed — "erc-20" has to mean "erc-20 ON THIS CHAIN", or selecting it under `base` would show mainnet's too and the sub-row counts would be global. So a sub-chip carries its group: `c8453|ERC-20`. */ let g=curGroup(); $('fc2').innerHTML=GROUP(g).map(x=>chipHtml(g+'|'+x,x.toLowerCase(), tally(r=>r.m.p===x&&groupOf(r.m)===g),String(KIND===g+'|'+x))).join(''); $('fc2').hidden=false} /* Built once; filtering only toggles [hidden]. Re-running innerHTML per keystroke would re-decode every inline SVG - the costliest thing here - and re-flash the art. */ let EMPTY=null,KIND='all'; function render(){ /* A filter chosen against the previous data set would otherwise persist across a reload and hide everything, with only "no listing matches" to explain it. */ KIND='all';summary(); $('grid').innerHTML=ROWS.map(card).join(''); EMPTY=document.createElement('p');EMPTY.className='ct';EMPTY.hidden=true; EMPTY.textContent='No listing matches that filter.';$('grid').append(EMPTY); paint()} /* Sorting sets each card's grid `order` rather than re-emitting the grid: the DOM and its decoded art stay put, so re-sorting costs a style recalc instead of a rebuild. */ /* Narrowing to one standard is a filter's job, so the standard chips are always on screen rather than behind a drill-down. Sorting by standard stays for the open-ended case — browsing a long list grouped by kind — and follows the registry's enum order, not the alphabet: A-Z would wedge BRC-20 between ERC-1155 and ERC-20 and scatter the Bitcoin formats through the Ethereum ones. Anything outside the taxonomy sorts last, so a future standard appears as a tail group instead of displacing Native. */ const ENUM=[...EVMS,...BTCS]; const ord=p=>{let i=ENUM.indexOf(p);return i<0?ENUM.length:i}; const SORTS={rank:(a,b)=>(b.m.r||0)-(a.m.r||0)||cmp(a,b), symbol:cmp,name:(a,b)=>String(a.m.n||'').localeCompare(String(b.m.n||''))||cmp(a,b), standard:(a,b)=>ord(a.m.p)-ord(b.m.p)||(b.m.r||0)-(a.m.r||0)||cmp(a,b), decimals:(a,b)=>(Number(b.m.d)||0)-(Number(a.m.d)||0)||cmp(a,b)}; function cmp(a,b){return String(a.m.s||'').localeCompare(String(b.m.s||''))} function paint(){let f=$('q').value.trim().toLowerCase(),n=0, /* Only real cards: the loading skeletons share `.p` for layout but carry no `data-i`, so a keystroke during the first load used to look them up in ROWS, get undefined and throw. Select by the attribute that makes a card a card. */ els=$('grid').querySelectorAll('.p[data-i]'), keep=r=>(!f||r.q.includes(f))&&(KIND==='all'||(KIND==='v'?r.m.v :KIND==='reserved'?r.m.x===false :KIND.includes('|')?(g=>inGroup(r.m,g[0])&&r.m.p===g[1])(KIND.split('|')) :inGroup(r.m,KIND))); for(let el of els){let r=ROWS[el.dataset.i];if(!r)continue;let show=keep(r);el.hidden=!show;if(show)n++} let order=ROWS.slice().sort(SORTS[$('sort').value]||SORTS.rank); /* Guard the lookup: a failed re-boot empties the grid, and without this the next keystroke indexes past the end of an empty NodeList and throws. */ order.forEach((r,pos)=>{let el=els[r.i];if(el)el.style.order=pos}); if(EMPTY)EMPTY.hidden=!!n||!ROWS.length; $('cnt').textContent=n+(n===ROWS.length?'':' of '+ROWS.length)+(n===1?' listing':' listings')} $('sort').onchange=paint; /* One handler for both rows: the tiers differ in what they offer, not in what a click means. Re-rendering the chips keeps counts, pressed state and the unfolded sub-row in agreement without three places having to remember each other. */ function onChip(e){let b=e.target.closest('button');if(!b)return; KIND=b.dataset.f;chips();paint()} $('fc').addEventListener('click',onChip); $('fc2').addEventListener('click',onChip); /* rAF-coalesced so a fast typist repaints once per frame, not once per keystroke. */ let tick=0; $('q').oninput=()=>{if(tick)return;tick=requestAnimationFrame(()=>{tick=0;paint()})}; function open_(i){let r=ROWS[i];if(!r)return;CUR=r; $('dkv').hidden=$('dla').hidden=false;$('dda').hidden=$('dnote').hidden=true; let m=r.m; $('dt').textContent=(m.s||'--')+' · listing '+m.i; /* The registry already carries desc, url, audit and extras; they were being fetched on every load and then thrown away. Show them rather than re-read them elsewhere. */ $('ddesc').textContent=m.desc||'';$('ddesc').hidden=!m.desc; let rows=[['name',m.n||'-'],['account',m.a||'(not deployed)'],['chain',chainLabel(m)], ['standard',m.p||'unknown'],['decimals',m.d],['curation weight',m.r], /* Same call the card makes, so the two can never disagree about a listing. */ ['provenance',chip(m)[1]], ['authoring',m.f?'sealed — cannot be re-authored':'open to the curator'], ['brand colour',hue(m)||'-']]; rows.push(['holder',holder(m)+(subject(m)?' — the token itself':' — the registry')]); /* Stated plainly because this page links out to a marketplace: every listing is born locked and stays locked, so a visitor who sees it on OpenSea should not have to discover from a reverted transaction that it was never for sale. */ rows.push(['transfer','locked — soulbound (ERC-5192)']); if(COLL(m))rows.push(['token art',m.o?'ids resolve to onchain svg':'not declared onchain']); if(m.u)rows.push(['url',m.u]); if(m.au)rows.push(['audit',m.au]); /* Extras are curator-authored key/value pairs, so their count and keys are unknown ahead of time - render whatever is there instead of a fixed set. */ for(let x of (Array.isArray(m.e)?m.e:[]))rows.push([x.k||'extra',x.v||'']); $('dkv').innerHTML=rows.map(([k,v])=>`<span>${esc(k)}</span><span>${esc(v)}</span>`).join(''); $('dlk').innerHTML=`<a href="${esc(osea(m))}" target=_blank rel="noopener noreferrer">view on opensea</a> · <a href="${esc(escan(m))}" target=_blank rel="noopener noreferrer">${subject(m)?'token on etherscan':'listing on etherscan'}</a>${safeUrl(m.u)?` · <a href="${esc(safeUrl(m.u))}" target=_blank rel="noopener noreferrer">project site</a>`:''}`; $('dj').textContent=JSON.stringify(r.m,null,1); document.querySelector('.db').scrollTop=0; if(!$('dlg').open)$('dlg').showModal()} /* Copying has two paths because the async Clipboard API is permission-gated: it is refused outright in a sandboxed frame and in several in-app wallet browsers. The legacy execCommand path is driven by the user gesture and needs no permission, so it still lands in most of those. If both fail, select the text — a reader can always copy a selection by hand, and "copy failed" with no recourse is a dead end. */ async function copyText(t,el){ try{await navigator.clipboard.writeText(t);return true}catch(e){} try{let ta=document.createElement('textarea');ta.value=t;ta.setAttribute('readonly',''); ta.style.cssText='position:fixed;top:0;left:-9999px'; document.body.appendChild(ta);ta.select(); let ok=document.execCommand('copy');ta.remove();if(ok)return tru
bel> <select id=sort aria-label="sort listings"> <option value=rank>curation weight</option> <option value=standard>token standard</option> <option value=symbol>symbol A–Z</option> <option value=name>name A–Z</option> <option value=decimals>decimals</option> </select> <span class=ct id=cnt></span> <span class=exp><button class=lk id=exTL title="Uniswap token list schema">token list json</button> · <button class=lk id=exRaw title="every field the registry holds, plus each listing's rendered card art">raw json</button></span> </div> <div class=fc id=fc role=group aria-label="filter by category"></div> <div class="fc fc2" id=fc2 role=group aria-label="filter by standard" hidden></div> <p id=msg></p> <div class=g id=grid></div> <footer> <p>Every card is rendered onchain by the registry's own renderer and decoded here — the same bytes a wallet or marketplace reads.</p> <p id=routes></p> <details><summary>Integrating</summary> <p>Every read is an ordinary <code>eth_call</code>; no key, no wallet, no indexer.</p> <pre id=devdoc></pre> </details> <p>Data source <span id=src>—</span> · <button class=lk id=setr aria-expanded=false aria-controls=rw>use your own RPC</button></p> <div class=rw id=rw hidden> <input id=rpcu type=url inputmode=url autocomplete=off spellcheck=false placeholder="https://your-node.example/rpc" aria-label="JSON-RPC endpoint for Ethereum mainnet"> <button class=bt id=rpcs>use it</button><button class=bt id=rpcc>reset</button> </div> </footer> </div> <dialog id=dlg aria-label="listing detail"><div class=dh><b id=dt></b><span><span id=dla><button class=lk id=dsvg>svg</button> · <button class=lk id=djson>json</button> · </span><span id=dda hidden><button class=lk id=ddl>download</button> · <button class=lk id=dcp>copy</button> · </span><button class=bt id=dx>close</button></span></div><div class=db><p class=dd id=ddesc hidden></p><p class=ln id=dlk></p><div class=kv id=dkv></div><p class=nb id=dnote hidden></p><pre id=dj></pre></div></dialog> <script> const L='0x0000006013df75a31678b786061c2b54bf531524', /* Keyless endpoints, each verified against this registry. Popular ones are absent where they answer eth_chainId but return nothing, or reject batches. */ RPCS=['https://eth.blockrazor.xyz','https://eth-mainnet.public.blastapi.io','https://ethereum-rpc.publicnode.com','https://rpc.mevblocker.io','https://eth.merkle.io','https://0xrpc.io/eth','https://eth.rpc.blxrbdn.com','https://eth.drpc.org','https://mainnet.gateway.tenderly.co','https://eth-pokt.nodies.app','https://eth.api.onfinality.io/public'], S={ids:'0xdf7ca268',json:'0x74e18e96',uri:'0xc87b56dd',curi:'0xe8a3d485',mc:'0xac9650d8'}, $=i=>document.getElementById(i), esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])), z=n=>BigInt(n).toString(16).padStart(64,'0'), short=u=>String(u).replace(/^https?:\/\//,'').replace(/\/.*$/,''); let RPC=null,ROWS=[],SEED=null,MARK='';const BAD=new Set(); async function post(u,b){let c=AbortSignal.timeout?AbortSignal.timeout(12000):undefined; let r=await fetch(u,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(b),signal:c}); if(!r.ok)throw Error('HTTP '+r.status);let j=await r.json();if(j&&j.error)throw Error(j.error.message||'rpc error');return j.result} /* The registry inherits solady's Multicallable, so ONE eth_call to multicall(bytes[]) carries every read. Beats JSON-RPC batching twice over: it is an ordinary eth_call, so endpoints that cap or reject batches still work - four below do - and it is one round trip. No Multicall3, no extra contract to trust. */ const W=x=>BigInt(x).toString(16).padStart(64,'0'); function mc(calls){let n=calls.length,offs=[],body='',cur=n*32; for(let c of calls){let d=c.slice(2),len=d.length/2,pad=(32-len%32)%32; offs.push(cur);body+=W(len)+d+'0'.repeat(pad*2);cur+=32+len+pad} return S.mc+W(32)+W(n)+offs.map(W).join('')+body} function unmc(hex){let h=(hex||'0x').slice(2);if(h.length<128)return[]; /* Offsets and lengths here come straight from an untrusted RPC, so bounds-check every read: an out-of-range word must abort, not silently slice out garbage. */ const w=i=>{let s=h.slice(i*64,(i+1)*64);if(s.length<64)throw Error('short return');return Number(BigInt('0x'+s))}; let arr=w(0)/32,n=w(arr),out=[]; if(!Number.isSafeInteger(arr)||!Number.isSafeInteger(n)||n*64>h.length)throw Error('bad return'); for(let i=0;i<n;i++){let p=arr+1+w(arr+1+i)/32,len=w(p); if(!Number.isSafeInteger(p)||(p+1)*64+len*2>h.length)throw Error('bad return'); out.push('0x'+h.slice((p+1)*64,(p+1)*64+len*2))} return out} /* An injected provider can stall forever (locked wallet); bound it and fail over. */ const deadline=(p,ms)=>Promise.race([p,new Promise((_,x)=>setTimeout(()=>x(Error('timeout')),ms))]); const wallet=(method,params)=>deadline(window.ethereum.request({method,params}),12000); async function raw(u,calls){let data=mc(calls); if(u==='wallet')return unmc(await wallet('eth_call',[{to:L,data},'latest'])); return unmc(await post(u,{jsonrpc:'2.0',id:1,method:'eth_call',params:[{to:L,data},'latest']}))} /* Round-robin the starting point so visitors spread across the pool rather than all leaning on the first entry, then fail over on error OR empty answer. */ const saved=()=>{try{return localStorage.getItem('tl.rpc')||''}catch(e){return''}}; function order(){let s=saved(),n=RPCS.length,o=Math.floor(Math.random()*n), ring=Array.from({length:n},(_,i)=>RPCS[(o+i)%n]); return (s?[s]:[]).concat(window.ethereum?['wallet']:[],ring.filter(u=>u!==s))} /* Concurrent chunk lanes all reach for an endpoint at once, and before they existed only one probe could ever be in flight. Without this, a single blip has three lanes walking the pool independently — three simultaneous probes, each able to mark a different endpoint BAD, so one hiccup can burn three of them. Share the attempt. */ let PICKING=null; function pick(){if(RPC&&SEED)return Promise.resolve(RPC); return PICKING||(PICKING=_pick().finally(()=>{PICKING=null}))} async function _pick(){ for(let u of order()){if(BAD.has(u))continue; /* Probe with the calls the page needs and keep the answer, so the probe IS wave one. An endpoint can answer eth_chainId and still return nothing useful. */ /* CREATE2 means this address can hold something else entirely on another chain. */ try{if(u==='wallet'&&BigInt(await wallet('eth_chainId',[]))!==1n)throw Error('wrong chain'); let r=await raw(u,[S.curi,S.ids]);if(!r[1]||r[1].length<130)throw Error('empty'); SEED=r;RPC=u;$('src').textContent=u==='wallet'?'your wallet':short(u);return u} catch(e){BAD.add(u)}} throw Error('No endpoint returned registry data.')} async function callMany(calls){ /* Every failure marks the endpoint BAD, so pick() throws once the pool is spent. */ for(;;){let u=await pick(); try{return await raw(u,calls)} catch(e){BAD.add(u);if(RPC===u){RPC=null;SEED=null}}}} /* One eth_call carries the whole registry only while the return fits an endpoint's response cap. Chunk, so a large registry costs a few round trips rather than one oversized call that every provider rejects. */ const CHUNK=48; const LANES=3; async function callChunked(calls){ if(calls.length<=CHUNK)return callMany(calls); /* Slice first, then run at most LANES in flight. Sequential was correct but slow — a large registry paid one full round trip per chunk. More lanes than this turns a single visitor into a burst against one keyless endpoint, which is how a pool entry starts refusing everyone. Results are written back by index, so the order the lanes finish in cannot reorder the listings. */ let parts=[]; for(let i=0;i<calls.length;i+=CHUNK)parts.push(calls.slice(i,i+CHUNK)); let out=new Array(parts.length),next=0,dead=null; await Promise.all(Array.from({length:Math.min(LANES,parts.length)},async()=>{ for(let i=next++;i<parts.length&&!dead;i=next++){ try{out[i]=await callMany(parts[i])}catch(e){dead=e;throw e}}})); return out.flat()} const cut=h=>(h||'0x').slice(2), bytesOf=h=>Uint8Array.from((cut(h).match(/../g)||[]),x=>parseInt(x,16)), utf8=u=>new TextDecoder().decode(u), b64=s=>utf8(Uint8Array.from(atob(s),c=>c.charCodeAt(0))); function str(h){h=cut(h);if(h.length<128)return'';let o=Number(BigInt('0x'+h.slice(0,64)))*2,n=Number(BigInt('0x'+h.slice(o,o+64)));return utf8(bytesOf('0x'+h.slice(o+64,o+64+n*2)))} /* `n` is a length word from an untrusted RPC and it sizes an allocation: without this bound a bogus word asks for an array of 2^64 entries and takes the tab down before any of it can be parsed. Require the ids to actually be present in the payload. */ function list(h){h=cut(h);if(h.length<128)return[]; let o=Number(BigInt('0x'+h.slice(0,64)))*2,n=Number(BigInt('0x'+h.slice(o,o+64))); if(!Number.isSafeInteger(o)||!Number.isSafeInteger(n)||o+64+n*64>h.length)throw Error('bad id list'); return Array.from({length:n},(_,i)=>BigInt('0x'+h.slice(o+64+i*64,o+128+i*64)))} /* Accepts a bare JSON string or a data: URI in either encoding the renderer may emit. */ function dataJson(u){if(!u.startsWith('data:'))return JSON.parse(u); let[head,...rest]=u.split(','),d=rest.join(','); return JSON.parse(/;base64/i.test(head)?b64(d):decodeURIComponent(d))} /* `sync` is permissionless but only possible for an EVM token on THIS chain with a non-zero account; everything else is owner-attested by construction, not by neglect. Naming which of those four cases applies is the honest version of a single "owner attested" badge - a reservation and a Bitcoin-rooted listing are unverifiable for very different reasons, and only one of them ever changes. */ function chip(m){ /* A listing whose json() did not parse knows nothing about itself. Saying "not readable from ethereum" here would assert a specific provenance — the Bitcoin case — about a listing we simply failed to read. */ if(m.bad)return['at','metadata unreadable']; if(m.v)return['on','metadata read onchain']; if(m.p==='Native')return['nc','no contract to read']; if(m.k!=='eip155')return['nc','not readable from ethereum']; if(Number(m.c)!==1)return['nc','lives on chain '+esc(m.c)]; return['at','owner attested']} /* The registry's Standard enum, grouped by the chain each format is rooted in. Held as a literal taxonomy rather than derived from the listings, so a category can be offered before its first listing exists — the point of the whole exercise. Labels match the renderer's `_standard()` exactly; a mismatch here would silently filter to nothing. Anything the registry gains that is not named below surfaces under `other` rather than vanishing from the filter. */ const EVMS=['Native','ERC-20','ERC-721','ERC-1155'],BTCS=['Tacit','Rune','Ordinal','BRC-20']; /* Chains are open-ended, so they are NOT advertised at zero the way the Bitcoin formats are — that list is a fixed contract enum, this one is not. A chain earns a chip by having a listing, and gets a human name if we know one. Anything unknown still groups correctly and reads "chain 999"; nothing has to be added here for a new chain to work, the name is the only thing this table buys. */ const CHAINS={1:'ethereum',10:'optimism',56:'bnb',100:'gnosis',130:'unichain',137:'polygon', 324:'zksync',480:'world',1868:'soneium',5000:'mantle',8453:'base',34443:'mode',42161:'arbitrum', 42220:'celo',43114:'avalanche',57073:'ink',59144:'linea',81457:'blast',534352:'scroll',7777777:'zora'}; /* Grouping is by CHAIN for EVM listings and by rooted chain otherwise. Grouping ERC-20 under "ethereum" was fine while mainnet was the only chain and a lie the moment a Base token is listed: a standard is not a chain. */ const groupOf=m=>m.k==='eip155'?'c'+m.c:BTCS.includes(m.p)?'bitcoin':m.k==='solana'?'solana':'other'; const GROUP=g=>g==='bitcoin'?BTCS:/^c\d+$/.test(g)?EVMS:null; const groupLabel=g=>/^c\d+$/.test(g)?(CHAINS[g.slice(1)]||'chain '+g.slice(1)):g; /* Art goes in an <img>, never innerHTML: SVG inside an img cannot run script or fire event handlers, so no renderer - present or future - can inject here. */ /* `t` is rendered from a uint24, so it is always #rrggbb - but it is injected into a style attribute, so prove it rather than trust it. */ const COLOR=/^#[0-9a-f]{6}$/i; const hue=m=>COLOR.test(m.t||'')?m.t:''; /* A listing's `url` is curator-authored and the renderer's `_safe` only strips quotes, angle brackets and control characters - it does NOT constrain the scheme, so `javascript:...` survives it intact. Escaping keeps that inside the attribute but would still run it on click, so allow only schemes that can navigate. Anything else is shown as text and never becomes a link. */ const safeUrl=u=>/^(https?|ipfs):\/\/[^\s]+$/i.test(String(u||''))?String(u):''; /* Same reasoning for logos. Inside an <img src> a hostile scheme is inert, but this value is also copied into the exported token list, where somebody else's app decides what to do with it — so it is constrained before it leaves here, not just before it is drawn. */ const safeImg=u=>/^(https:\/\/|ipfs:\/\/|data:image\/)/i.test(String(u||''))?String(u):''; /* Flags the registry carries that the card never showed. Each is a real claim about the listing's standing, not decoration: `pending` has no token behind it yet, `sealed` can never be re-authored, and `o` says the LISTED COLLECTION's own token ids resolve to data-SVG - a claim about that collection's art, not about this card's. The contract only lets it mean anything on a collection, so the wording follows the renderer's ("ERC-721 / ONCHAIN TOKEN SVG") rather than inventing one. */ const COLL=m=>m.p==='ERC-721'||m.p==='ERC-1155'; /* `raw:0` is what the registry stores for anything non-EVM, which is true but tells a reader nothing; and an unreadable listing has no namespace at all. Name the chain the taxonomy knows about instead of printing the raw pair. */ const chainLabel=m=>m.k==='eip155'?(CHAINS[m.c]?CHAINS[m.c]+' · eip155:'+m.c:'eip155:'+m.c) :m.k==='solana'?'solana':GROUP(groupOf(m))?groupLabel(groupOf
<!doctype html><html lang=en><meta charset=utf-8> <!-- token.list.wei — an onchain token list. This document renders client-side, so an agent reading this HTML sees no listings. The data is not behind an API; it is three eth_calls against one mainnet contract, no key and no indexer: registry 0x0000006013df75a31678b786061c2b54bf531524 (Ethereum mainnet) ids rankedIds()(uint256[]) — every listing id, curation order metadata json(uint256)(string) — one listing, already JSON card art tokenURI(uint256)(string) — ERC-721 metadata; art is .image batched multicall(bytes[])(bytes[]) — all of the above in one call If you can run scripts, `window.tokenlist` holds the decoded result after load: {registry, chainId, source, fetchedAt, listings:[{...fields, art}]}. The same shape is downloadable from the page as `raw json`. --> <meta name=description content="An onchain token list on Ethereum. Every listing is an NFT minted to the token it describes, with metadata and card art read from the chain."><meta name=viewport content="width=device-width,initial-scale=1,viewport-fit=cover"> <title>token.list.wei</title> <link id=fav rel=icon href="data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2032%2032'%3E%3Crect%20width%3D'32'%20height%3D'32'%20fill%3D'%23000'%2F%3E%3Cg%20fill%3D'none'%20stroke%3D'%23fff'%20stroke-width%3D'2'%3E%3Crect%20x%3D'3'%20y%3D'3'%20width%3D'26'%20height%3D'26'%2F%3E%3Cpath%20d%3D'M3%2012h26M3%2022h26'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"> <style> :root{color-scheme:light dark;--bg:#faf8f5;--pn:#fff;--ink:#1a1815;--mu:#6b6560;--hr:#e3ddd4;--ac:#4a63c4;--at:#b96908;--nt:#5e7a6b; --sa:"Helvetica Neue",Helvetica,Arial,sans-serif;--mo:ui-monospace,SFMono-Regular,Menlo,monospace} @media(prefers-color-scheme:dark){:root{--bg:#121110;--pn:#1b1917;--ink:#efeae3;--mu:#9a928a;--hr:#2e2a26;--ac:#8ca0f0;--at:#f7931a;--nt:#8fb3a0}} *{box-sizing:border-box} [hidden]{display:none!important} html{-webkit-text-size-adjust:100%;overflow-x:hidden} body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--sa);line-height:1.5;-webkit-font-smoothing:antialiased;overflow-wrap:anywhere} .w{max-width:1180px;margin:0 auto;padding:clamp(20px,5vw,60px) max(16px,env(safe-area-inset-left)) calc(72px + env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-right))} @media(min-width:720px){.w{padding-left:clamp(24px,4vw,40px);padding-right:clamp(24px,4vw,40px)}} .eb{font-family:var(--mo);font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--mu);margin:0 0 14px} header{display:flex;flex-wrap:wrap;gap:clamp(16px,4vw,40px);align-items:flex-start;padding-bottom:24px;border-bottom:1px solid var(--hr)} .mk{width:clamp(76px,15vw,152px);flex:none}.mk svg,.mk img{width:100%;height:auto;display:block} .ld{flex:1 1 340px;min-width:min(100%,260px);display:flex;flex-direction:column;gap:10px} h1{margin:0;font-size:clamp(21px,4.4vw,38px);font-weight:700;letter-spacing:-.022em;line-height:1.18;text-wrap:balance} .sb{margin:0;color:var(--mu);max-width:62ch;font-size:clamp(14px,1.4vw,15px)} .fx{display:flex;flex-wrap:wrap;gap:4px 16px;font-family:var(--mo);font-size:11.5px;color:var(--mu);font-variant-numeric:tabular-nums} .fx b{color:var(--ink);font-weight:500}.fx a{color:var(--ac)} /* REGISTER SUMMARY - every figure is counted from the listings already fetched, so it costs no extra call and cannot disagree with the grid below it. */ .sm{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:1px;margin:18px 0 0; border:1px solid var(--hr);border-radius:3px;background:var(--hr);overflow:hidden} /* Grid + a 1px gap over a rule-coloured ground draws the hairlines: with flex and border-right, a wrapped second row sat under the first with nothing between them. */ .sm div{background:var(--pn);padding:10px 13px;display:flex;flex-direction:column;gap:3px} .sm b{font-family:var(--mo);font-size:17px;font-weight:500;letter-spacing:-.02em;font-variant-numeric:tabular-nums} .sm span{font-family:var(--mo);font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--mu)} .bar{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin:20px 0 0} .fc{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0 0} .fc button{font-family:var(--mo);font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;padding:4px 9px;border-radius:2px; border:1px solid var(--hr);background:none;color:var(--mu);cursor:pointer;min-height:28px} .fc button:hover{color:var(--ink)} .fc button[aria-pressed=true]{color:var(--ac);border-color:var(--ac)} .fc button:focus-visible{outline:2px solid var(--ac);outline-offset:1px} .fc button b{font-weight:400;margin-left:6px;opacity:.6;font-variant-numeric:tabular-nums} /* A category with nothing in it is still worth showing — it says the register knows the format. Muted so it reads as "none yet" rather than as a live filter. */ /* Fading to .45 put these under the contrast floor on a dark ground. Keep them clearly secondary, but readable — "bitcoin 0" is meant to be read. */ .fc button.z{opacity:.7;border-style:dashed} /* The group that contains the active standard: related to the selection, but not itself the filter, so it is marked without claiming aria-pressed. */ .fc button.pa{border-color:var(--ac)} /* The sub-row is subordinate: inset behind a rule, so it reads as belonging to the selection above rather than as a second, competing set of filters. */ .fc2{margin-top:6px;padding-left:11px;border-left:2px solid var(--hr)} .fc2 button{font-size:10px} /* Native select chrome differs per browser and per platform — on iOS it adds its own padding and can crowd the chevron into the text. Draw the chevron instead, the way zSwap already does, so the control is the same everywhere and the arrow sits where the reserved padding says it does. The chevron inherits currentColor, so it tracks the theme without a second asset. */ #sort{appearance:none;-webkit-appearance:none;font:inherit;font-family:var(--mo);font-size:11.5px; color:var(--ink);background:var(--pn);border:1px solid var(--hr);border-radius:3px; padding:5px 22px 5px 8px;min-height:28px;cursor:pointer; background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%); background-position:calc(100% - 13px) calc(50% + 1px),calc(100% - 8px) calc(50% + 1px); background-size:5px 5px,5px 5px;background-repeat:no-repeat} #sort:focus-visible{outline:2px solid var(--ac);outline-offset:-1px} #sort::-ms-expand{display:none} #q{flex:1 1 200px;min-width:0;background:var(--pn);color:var(--ink);border:1px solid var(--hr);border-radius:3px;padding:10px 12px;font-family:var(--mo);font-size:16px} @media(min-width:720px){#q{font-size:13px;padding:9px 12px}} #q:focus-visible{outline:2px solid var(--ac);outline-offset:-1px} .ct,.exp{font-family:var(--mo);font-size:11.5px;color:var(--mu);flex:none} #msg{margin:14px 0 0;font-family:var(--mo);font-size:12.5px;color:var(--at)} .g{display:grid;gap:clamp(14px,2.4vw,26px);grid-template-columns:repeat(auto-fill,minmax(min(300px,100%),1fr));margin-top:20px} /* Every card carries a ~4KB inline SVG, so a long list means decoding all of them at once. `content-visibility` defers that until a card nears the viewport; the intrinsic size keeps the scrollbar honest in the meantime and is remembered once a card has been laid out for real. Filtering still works: [hidden] wins over this. */ .p{content-visibility:auto;contain-intrinsic-size:320px;contain-intrinsic-size:auto 320px; margin:0;background:var(--pn);border:1px solid var(--hr);border-radius:3px;overflow:hidden;display:flex;flex-direction:column;cursor:pointer; transition:border-color .14s ease,transform .14s ease,box-shadow .14s ease} @media(hover:hover){.p:hover{border-color:var(--ac);transform:translateY(-2px);box-shadow:0 6px 20px -10px #0006} .p:hover .sy{color:var(--ac)}} .p:focus-visible{outline:2px solid var(--ac);outline-offset:2px} .p:active{transform:none} @media(prefers-reduced-motion:reduce){.p{transition:none}.p:hover{transform:none}} /* The rail is the token's own `t` colour, straight from the registry - the one place each card is allowed to look like itself rather than like the page. */ .p::before{content:"";display:block;height:3px;background:var(--b,var(--hr))} .lg{width:16px;height:16px;border-radius:50%;flex:none;background:var(--hr)} /* Rank is a curation ordering, so it is drawn against the observed spread rather than as a fraction of its raw value - the ranks cluster near 1e6 and a raw bar reads flat. */ .rkw{display:flex;align-items:center;gap:8px} .rkn{font-family:var(--mo);font-size:10px;color:var(--mu);flex:none;font-variant-numeric:tabular-nums} .rk{height:2px;background:var(--hr);border-radius:1px;overflow:hidden;flex:1} .rk i{display:block;height:100%;background:var(--b,var(--ac));min-width:2px} .art{background:#000;line-height:0;aspect-ratio:12/7} .art img{width:100%;height:100%;display:block;animation:fi .18s ease both} @keyframes fi{from{opacity:0}to{opacity:1}} @media(prefers-reduced-motion:reduce){.art img{animation:none}} figcaption{padding:11px 13px 13px;display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--hr)} .r{display:flex;align-items:center;gap:8px;flex-wrap:wrap} .sy{font-weight:700;font-size:15px;transition:color .14s ease} .sd{font-family:var(--mo);font-size:11.5px;color:var(--mu);margin-left:auto} .c{font-family:var(--mo);font-size:10px;letter-spacing:.05em;text-transform:uppercase;padding:2px 7px;border-radius:2px;border:1px solid currentColor;white-space:nowrap} .on{color:var(--ac)}.at{color:var(--at)}.nc{color:var(--nt)} .cp{background:none;border:0;padding:6px 0;margin:-6px 0 -4px;font-family:var(--mo);font-size:10.5px;color:var(--mu);line-height:1.45;cursor:copy;text-align:left;min-height:32px;width:100%} .cp:hover,.cp:focus-visible{color:var(--ink)} .ln{display:flex;flex-wrap:wrap;gap:0 6px;align-items:center;font-family:var(--mo);font-size:10.5px;margin:2px 0 0;color:var(--mu)} .ln a,.ln button{color:var(--ac);text-decoration:none;padding:3px 0;min-height:24px;display:inline-flex;align-items:center} @media(pointer:coarse){.ln a,.ln button{min-height:34px;padding:6px 0}.ln{gap:0 10px}} .ln a:hover,.ln button:hover,.ln a:focus-visible,.ln button:focus-visible{text-decoration:underline} .db .ln{font-size:11.5px;margin:0 0 12px} .sk{background:linear-gradient(90deg,var(--pn),var(--hr),var(--pn));background-size:200% 100%;animation:sh 1.4s linear infinite} @keyframes sh{to{background-position:-200% 0}} @media(prefers-reduced-motion:reduce){.sk{animation:none}} footer{margin-top:44px;padding-top:18px;border-top:1px solid var(--hr);color:var(--mu);font-size:12.5px;max-width:76ch} footer a,.lk{color:var(--ac)} footer code{font-family:var(--mo);font-size:11px} footer p{margin:0 0 8px} footer details{margin:10px 0 0} footer summary{cursor:pointer;color:var(--ac);font-family:var(--mo);font-size:11.5px} footer pre{margin:8px 0 0;padding:10px;background:var(--pn);border:1px solid var(--hr);border-radius:3px;font-family:var(--mo);font-size:10.5px;line-height:1.6;overflow-x:auto;white-space:pre;color:var(--mu)} .lk{background:none;border:0;padding:0;font:inherit;cursor:pointer;text-decoration:underline} .rw{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:8px 0 0} #rpcu{flex:1 1 260px;min-width:0;background:var(--pn);color:var(--ink);border:1px solid var(--hr);border-radius:3px;padding:9px 10px;font-family:var(--mo);font-size:16px} @media(min-width:720px){#rpcu{font-size:12px;padding:7px 10px}} #rpcu:focus-visible{outline:2px solid var(--ac);outline-offset:-1px} .bt{background:none;border:1px solid var(--hr);color:var(--mu);border-radius:3px;padding:7px 12px;cursor:pointer;font-family:var(--mo);font-size:12px;min-height:36px} .bt:hover,.bt:focus-visible{color:var(--ink);border-color:var(--ac)} dialog{border:1px solid var(--hr);border-radius:4px;background:var(--pn);color:var(--ink);width:min(760px,100%);max-width:100%;padding:0;margin:auto} dialog::backdrop{background:#000a} @media(max-width:640px){dialog{margin:auto auto 0;border-radius:8px 8px 0 0;border-bottom:0;width:100%}} .dh{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:12px 14px;border-bottom:1px solid var(--hr);position:sticky;top:0;background:var(--pn)} .dh b{font-size:15px} .dh>span{display:flex;gap:8px;align-items:center;font-family:var(--mo);font-size:12px;color:var(--mu)} #dla,#dda{display:contents} .db{padding:14px;max-height:min(70vh,560px);overflow:auto;-webkit-overflow-scrolling:touch} .db pre{margin:0;font-family:var(--mo);font-size:11px;white-space:pre-wrap;color:var(--mu);user-select:all;-webkit-user-select:all} .nb{margin:0 0 10px;font-family:var(--mo);font-size:11px;line-height:1.5;color:var(--at)} .dd{margin:0 0 12px;font-size:14px;line-height:1.55;max-width:64ch;color:var(--ink)} .kv{display:grid;grid-template-columns:auto 1fr;gap:4px 12px;font-family:var(--mo);font-size:12px;margin-bottom:12px} .kv span:nth-child(odd){color:var(--mu)} </style> <div class=w> <p class=eb>token.list.wei / canonical onchain tokenlist</p> <header> <div class=mk id=mark></div> <div class=ld> <h1>The whole list lives onchain</h1> <p class=sb id=desc>An onchain token list. Each listing is an ERC-721 minted to the token it describes, carrying its logo, symbol, decimals and links. For tokens on this chain the name, symbol and decimals are read from the token contract itself and cannot be authored by the curator; anyone may refresh them.</p> <div class=fx> <span>registry <a id=lnk target=_blank rel=noopener><b id=addr></b></a></span> <span>art + metadata <b>100% onchain</b></span> <span>listings <b>non-transferable</b> (<a href="https://eip.tools/eip/5192" target=_blank rel="noopener noreferrer">ERC-5192</a>)</span> <span id=pgf></span> </div> </div> </header> <div class=sm id=sm hidden></div> <div class=bar> <input id=q placeholder="filter by symbol, name or address" autocomplete=off spellcheck=false aria-label="filter listings"> <label class=ct for=sort>sort</la
="16" cy="16" r="16" fill="#627E`EA"/><g fill="#FFF" fill-rule="n`onzero"><path fill-opacity=".602`" d="M16.498 4v8.87l7.497 3.35z"a/><path d="M16.498 4L9 16.22l7.4a98-3.35z"/><path fill-opacity=".a602" d="M16.498 21.968v6.027L24 a17.616z"/><path d="M16.498 27.99a5v-6.028L9 17.616z"/><path fill-aopacity=".2" d="M16.498 20.573l7a.497-4.353-7.497-3.348z"/><path afill-opacity=".602" d="M9 16.22la7.498 4.353v-7.701z"/></g></g></ahttps://ethereum.orgThe native asset of Ethereum. Us` ed for gas, and held at address iewBox="0 0 32 32"><circle cx="1``6" cy="16" r="16" fill="#627EEA"`/><g stroke="#FFF" stroke-opacit`y=".9" stroke-width="1.7" stroke`-linecap="round" stroke-linejoin`="round" fill="none"><path d="M1a1 5.6H7.9A2.3 2.3 0 0 0 5.6 7.9Va11"/><path d="M21 5.6h3.1A2.3 2.a3 0 0 1 26.4 7.9V11"/><path d="Ma11 26.4H7.9A2.3 2.3 0 0 1 5.6 24a.1V21"/><path d="M21 26.4h3.1a2.a3 2.3 0 0 0 2.3-2.3V21"/></g><g afill="#FFF" fill-rule="nonzero" atransform="translate(16 16) scalae(0.56) translate(-16 -16)"><patah fill-opacity=".602" d="M16.498a 4v8.87l7.497 3.35z"/><path d="M16.498 4L9 16.22l7.498-3.35z"/><apath fill-opacity=".602" d="M16.a498 21.968v6.027L24 17.616z"/><paath d="M16.498 27.995v-6.028L9 1a7.616z"/><path fill-opacity=".2"a d="M16.498 20.573l7.497-4.353-7a.497-3.348z"/><path fill-opacitya=".602" d="M9 16.22l7.498 4.353va-7.701z"/></g></svg>Rnhttps://weth.io`Ether wrapped as an ERC-20, rede` 5.424-5.402.244-.121.365-.303.3a"><circle fill="#2775CA" cx="16"` cy="16" r="16"/><g fill="#FFF">`<path d="M20.022 18.124c0-2.124-`1.28-2.852-3.84-3.156-1.828-.243`-2.193-.728-2.193-1.578 0-.85.61a-1.396 1.828-1.396 1.097 0 1.707a.364 2.011 1.275a.458.458 0 00.4a27.303h.975a.416.416 0 00.427-.4a25v-.06a3.04 3.04 0 00-2.743-2.4a89V9.142c0-.243-.183-.425-.487-.a486h-.915c-.243 0-.426.182-.487.a486v1.396c-1.829.242-2.986 1.456a-2.986 2.974 0 2.002 1.218 2.791a 3.778 3.095 1.707.303 2.255.668a 2.255 1.639 0 .97-.853 1.638-2.a011 1.638-1.585 0-2.133-.667-2.316-1.578-.06-.242-.244-.364-.427a-.364h-1.036a.416.416 0 00-.426.a425v.06c.243 1.518 1.219 2.61 3.a23 2.914v1.457c0 .242.183.425.48a7.485h.915c.243 0 .426-.182.487-a.485V21.34c1.829-.303 3.047-1.57a8 3.047-3.217z"/><path d="M12.89a2 24.497c-4.754-1.7-7.192-6.98-5a.424-11.653.914-2.55 2.925-4.491a65-.607v-.85c0-.242-.121-.424-.3a65-.485-.061 0-.183 0-.244.06a10a.895 10.895 0 00-7.13 13.717c1.0a96 3.4 3.717 6.01 7.13 7.102.244a.121.488 0 .548-.243.061-.06.061a-.122.061-.243v-.85c0-.182-.182-a.424-.365-.546zm6.46-18.936c-.24a4-.122-.488 0-.548.242-.061.061-a.061.122-.061.243v.85c0 .243.182a.485.365.607 4.754 1.7 7.192 6.9a8 5.424 11.653-.914 2.55-2.925 4a.491-5.424 5.402-.244.121-.365.3a03-.365.607v.85c0 .242.121.424.3a65.485.061 0 .183 0 .244-.06a10.a895 10.895 0 007.13-13.717c-1.09a6-3.46-3.778-6.07-7.13-7.162z"/>ahttps://circle.com/usdcDollar stablecoin issued by Circ` 82h3.913v-7.584c4.393-.202 7.694a="16" cy="16" r="16" fill="#26A1`7B"/><path fill="#FFF" d="M17.92`2 17.383v-.002c-.11.008-.677.042`-1.942.042-1.01 0-1.721-.03-1.97a1-.042v.003c-3.888-.171-6.79-.84a8-6.79-1.658 0-.809 2.902-1.486 a6.79-1.66v2.644c.254.018.982.061a 1.988.061 1.207 0 1.812-.05 1.9a25-.06v-2.643c3.88.173 6.775.85 a6.775 1.658 0 .81-2.895 1.485-6.a775 1.657m0-3.59v-2.366h5.414V7.a819H8.595v3.608h5.414v2.365c-4.4a.202-7.709 1.074-7.709 2.118 0 1a.044 3.309 1.915 7.709 2.118v7.5a-1.073 7.694-2.116 0-1.043-3.301a-1.914-7.694-2.117"/></g></svg>Rphttps://tether.to`xDollar stablecoin issued by Teth` ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_a%,W[a% W[Pa$=_Q` aaYPV[aR}V[_Q` a^^_9_Q_R` `@Qgactivate`aN'V[a"ɄaRFV[a"ӄ0aR}V[yhttp://www.w3.org/2000/svg`0[yhttp://www.w3.org/2000/svg`0ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_5a3Oa6SV[a3WaJ:V[`RlToken Listing`aZ7V[aZ䑅aZ7V[_3<svg xmlns="http://www.w3.org/20" fill-rule="evenodd"><circle cx00/svg" width="20" height="20" viewBox="0 0 32 32"><g fill="none
00/svg' viewBox='0 0 420 420' ro`@le='img'><title>Token Listing</t``itle><rect width='420' height='4`20' fill='#000'/><g fill='none' `stroke='#fff' stroke-width='2'><`rect x='18' y='18' width='384' h`eight='384'/><path d='M18 128h38a4M18 312h384'/></g><g fill='#fffa' font-family='Helvetica,Arial,saans-serif' text-anchor='middle'>a<text x='210' y='90' font-size='a30' font-weight='700'>TOKEN</texat><text x='210' y='232' font-sizae='58' font-weight='700'>LIST</taext><text x='210' y='362' font-saize='15' opacity='0.7'>ONCHAIN</a{"name":"Token Listing","description":"An onchain token list. Ea`@ch listing is an ERC-721 minted ``to the token it describes, carry`ing its logo, symbol, decimals a`nd links. For tokens on this cha`in the name, symbol and decimals` are read from the token contracat itself and cannot be authored aby the curator; anyone may refrea<rect x='32' y='110' width='112'` Rs height='112' fill='``' opacity='0.12'/><rect x='32' y='110' width='112' height='112' `tRsfill='none' stroke='``' stroke-width='1' opacity='0.5'<g><rect x='32' y='64' height='20' rx='4' fill-opacity='0.16' stzroke-opacity='0.55' width='`('/><text x='39' y='78' font-family='Helvetica,Arial,sans-serif' tfont-size='11' fill='`X<g fill='#fff' font-family='Helvetica,Arial,sans-serif'><text x='32' y='55' font-size='25' font-weight='700'>TOKEN LISTING</text><text x='688' y='55' text-anchor='end' font-size='12' fill='</text><text x='688' y='77' text-anchor='end' font-size='12' opa<text x='176' y='158' font-size=y' font-weight='700' fill='`0</text><text x='176' y='188' fon</text><text x='176' y='212' fonp' y='226' width='`xz' opacity='0.45'/><text x='`(00/svg' viewBox='0 0 720 420' ro token listing</title><rect widt`ph='720' height='420' fill='#000'`/><g fill='none' stroke='#fff' s`troke-width='2'><rect x='18' y='`Ђ18' width='684' height='384'/><p`ath d='M18 88h684M18 356h684'/><a / Token Listing","description":","attributes":[{"trait_type":"S"},{"trait_type":"Decimals","val},{"trait_type":"Token Standard""},{"trait_type":"Per-token Artw"},{"trait_type":"Chain","value""},{"trait_type":"Source","value"},{"trait_type":"Deployment","v"},{"trait_type":"Curation","val"},{"trait_type":"Sort Weight","},{"trait_type":"Audit","value":<text x='688' y='382' text-anchor='end' font-size='12' opacity='`@0.7' text-decoration='underline'``<text x='32' y='382' font-size='12' opacity='0.7' text-decoratio`@p' y='226' width='`xz' opacity='0.45'/><text x='`(<image x='40' y='118' width='96' height='96' preserveAspectRatio`@Rv='xMidYMid meet' href='`Ho<text x='32' y='`' font-family='ui-monospace,SFMono-Regular,Menlo,monospace' font`0<text x='32' y='258' font-size='11' opacity='0.6'>ADDRESS</text>`@<text x='32' y='278' font-size='``<rect x='18' y='18' width='684' ` height='384' fill='#000' opacity`@='0.64'/><rect x='32' y='300' wi``dth='656' height='52' fill='#d7d`7d7'/><g fill='#000' font-family`='Helvetica,Arial,sans-serif'><t`ext x='48' y='322' font-size='15`' font-weight='700'>RESERVED TOKaEN / NOT DEPLOYED</text><text x=a'48' y='341' font-size='12'>ADDRaESS PENDING - NOT AVAILABLE FOR aTRANSFERS, QUOTES, OR SWAPS</texaABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_Ro0123456789abcdef`123456789ABCDEFGHJKLMNPQRSTUVWXY`11111111111111111111111111111111`Ro0123456789abcdef`thttps://ipfs.io/ipfs/`XR{ERC-1155 / ONCHAIN TOKEN SVG` RzERC-721 / ONCHAIN TOKEN SVG`(Ro0123456789abcdef`' y='239' font-family='Helvetica,Arial,sans-serif' font-size='11<svg xmlns='http://www.w3.org/20' height='18' rx='3' fill='none'
00/svg' viewBox='0 0 420 420' ro`@le='img'><title>Token Listing</t``itle><rect width='420' height='4`20' fill='#000'/><g fill='none' `stroke='#fff' stroke-width='2'><`rect x='18' y='18' width='384' h`eight='384'/><path d='M18 128h38a4M18 312h384'/></g><g fill='#fffa' font-family='Helvetica,Arial,saans-serif' text-anchor='middle'>a<text x='210' y='90' font-size='a30' font-weight='700'>TOKEN</texat><text x='210' y='232' font-sizae='58' font-weight='700'>LIST</taext><text x='210' y='362' font-saize='15' opacity='0.7'>ONCHAIN</a{"name":"Token Listing","description":"An onchain token list. Ea`@ch listing is an ERC-721 minted ``to the token it describes, carry`ing its logo, symbol, decimals a`nd links. For tokens on this cha`in the name, symbol and decimals` are read from the token contracat itself and cannot be authored aby the curator; anyone may refrea<rect x='32' y='110' width='112'Rz height='112' rx='8' fill='`(' opacity='0.07'/><rect x='32' y='110' width='112' height='112' `{Rzrx='8' fill='none' stroke='`(' stroke-width='1' opacity='0.22<g fill='#fff' font-family='Helvetica,Arial,sans-serif'><text x=`@'32' y='55' font-size='25' font-``weight='700'>TOKEN LISTING</text`><text x='688' y='55' text-ancho`</text><text x='688' y='77' text-anchor='end' font-size='12' opaa<text x='176' y='158' font-size=y' font-weight='700' fill='`0</text><text x='176' y='188' fon</text><text x='176' y='212' fonp' y='226' width='`xn fill-opacity='`00/svg' viewBox='0 0 720 420' ro token listing</title><rect widt`ph='720' height='420' fill='#000'`/><g fill='none' stroke='#fff' s`troke-width='2'><rect x='18' y='`Ђ18' width='684' height='384'/><p`ath d='M18 88h684M18 356h684'/><a / Token Listing","description":","attributes":[{"trait_type":"S"},{"trait_type":"Decimals","val},{"trait_type":"Token Standard""},{"trait_type":"Per-token Artw"},{"trait_type":"Chain","value""},{"trait_type":"Source","value"},{"trait_type":"Deployment","v"},{"trait_type":"Curation","val"},{"trait_type":"Sort Weight","},{"trait_type":"Audit","value":<text x='688' y='382' text-ancho0.7' text-decoration='underline'``<text x='32' y='382' font-size='12' opacity='0.7' text-decoratioa<image x='40' y='118' width='96' height='96' preserveAspectRatio`@Rv='xMidYMid meet' href='`Ho<text x='32' y='`' font-size='11' opacity='0.6'>ADDRESS</text><text x='32' y='o<text x='32' y='`' font-family='ui-monospace,SFMono-Regular,Menlo,monospace' font`0<rect x='18' y='18' width='684' ` height='384' fill='#000' opacity`@='0.64'/><rect x='32' y='300' wi``dth='656' height='52' fill='#d7d`7d7'/><g fill='#000' font-family`='Helvetica,Arial,sans-serif'><t`ext x='48' y='322' font-size='15`' font-weight='700'>RESERVED TOKaEN / NOT DEPLOYED</text><text x=a'48' y='341' font-size='12'>ADDRaESS PENDING - NOT AVAILABLE FOR aTRANSFERS, QUOTES, OR SWAPS</texaABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_a2|W[Pa2SW`@Qa27`@Ro0123456789abcdef`123456789ABCDEFGHJKLMNPQRSTUVWXY`11111111111111111111111111111111`Ro0123456789abcdef`thttps://ipfs.io/ipfs/`XR{ERC-1155 / ONCHAIN TOKEN SVG` RzERC-721 / ONCHAIN TOKEN SVG`(p' y='226' width='`xn fill-opacity='`Ro0123456789abcdef`' stroke='#fff' stroke-opacity='' y='239' font-family='Helvetica,Arial,sans-serif' font-size='11<svg xmlns='http://www.w3.org/20r='end' font-size='12' opacity='' height='18' rx='3' fill='#fff'
o<text x='32' y='`' font-family='ui-monospace,SFMono-Regular,Menlo,monospace' font`0<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 720 420'><rect width='720' height='420' fill='#000'/><g fill='none' stroke='#fff' stroke-width='2'><rect x='18' y='18' width='684' height='384'/><path d='M18 88h684M18 356h684'/></g><rect x='32' y='110' width='112' height='112' fill='' opacity='0.12'/><rect x='32' ya='110' width='112' height='112' aRsfill='none' stroke='``' stroke-width='1' opacity='0.5'<g fill='#fff' font-family='Helvetica,Arial,sans-serif'><text x='32' y='55' font-size='25' font-weight='700'>TOKEN LISTING</text><text x='32' y='77' font-size='</text><text x='688' y='55' text-anchor='end' font-size='12' fil</text><text x='688' y='77' text-anchor='end' font-size='12' opa</text><text x='176' y='158' font-size='40' font-weight='700' fi</text><text x='176' y='188' fon</text><text x='176' y='212' fon</text><text x='32' y='250' font-size='11' opacity='0.6'>ADDRESS</text><text x='32' y='272' font<text x='32' y='382' font-size=' / Token Listing","description":","attributes":[{"trait_type":"S"},{"trait_type":"Decimals","val},{"trait_type":"Token Standard""},{"trait_type":"Per-token Artw"},{"trait_type":"Chain","value""},{"trait_type":"Source","value"},{"trait_type":"Deployment","v"},{"trait_type":"Sort Weight","},{"trait_type":"Audit","value":<text x='688' y='382' text-anchor='end' font-size='12' opacity='`@<image x='40' y='118' width='96'Rr height='96' href='`h<rect x='18' y='18' width='684' ` height='384' fill='#000' opacity`@='0.64'/><rect x='32' y='278' wi``dth='656' height='54' fill='#d7d`7d7'/><g fill='#000' font-family`='Helvetica,Arial,sans-serif'><t`ext x='48' y='302' font-size='15`' font-weight='700'>RESERVED TOKaEN / NOT DEPLOYED</text><text x=a'48' y='321' font-size='12'>ADDRaESS PENDING - NOT AVAILABLE FOR aTRANSFERS, QUOTES, OR SWAPS</texaRo0123456789abcdef`Ro0123456789abcdef`123456789ABCDEFGHJKLMNPQRSTUVWXY`11111111111111111111111111111111`Ro0123456789abcdef`R{ERC-1155 / ONCHAIN TOKEN SVG` RzERC-721 / ONCHAIN TOKEN SVG`(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789-_
`@Ro0123456789abcdef` GUARDIAN POISON PILL. Grant the src_co guardian multisig ONE non`@-transferable, single-use permit`` (op 1 / delegatecall) to run FW`CPoisonPill.pull() at . One pull redeems every FW NFT the collector vault holds ( today) back to TokenWorks S02 for its unvested partial refund, `[then sweeps the vault's entire E`{TH balance into this DAO's treas`ury. Amounts are read at executi`on time, not fixed here: ~ milliETH recoverable today, decaying to the vault balance alone`ڂ once the S02 vesting window clo`ses. The guardian chooses only tahe moment. It cannot name a reciapient, an amount, or a token: alal proceeds land in the treasury apro-rata to every holder. Purposae: liquidate the collection for athe benefit of all holders, and aprotect minority exit rights agaainst continuous-sale manipulatioan or takeover of the vault portfaolio. Revocable by this DAO at aany time via setPermit(count 0) oa`@Ro0123456789abcdef` Ro0123456789abcdef`Ro0123456789abcdef`<<<PROPOSAL_DATA { "type": "PROPOSAL", ", "value": "0", ", "description": "" } PROPOSAL_DATA>>>
remint permit(s) to FWCKeeper. Each use spends exactly 1 ETH of`F vault funds on another TokenWor`fks pass, which is held by the va``@Ro0123456789abcdef` Ro0123456789abcdef`Ro0123456789abcdef`<<<PROPOSAL_DATA { "type": "PROPOSAL", ", "value": "0", ", "description": "" } PROPOSAL_DATA>>> FWAcore fee-claim permit(s) to FWCKeeper. Each use sweeps pass `F fees into the vault. Proceeds are paid to the vault regardless `a`@Ro0123456789abcdef` Ro0123456789abcdef`Ro0123456789abcdef`<<<PROPOSAL_DATA { "type": "PROPOSAL", ", "value": "0", ", "description": "" } PROPOSAL_DATA>>>a+UV[a0pV[P`@Qg ඳ
remint permit(s) to FWCKeeper. Each use spends exactly 1 ETH of`F vault funds on another TokenWor`fks pass, which is held by the va``@Ro0123456789abcdef` Ro0123456789abcdef`Ro0123456789abcdef`<<<PROPOSAL_DATA { "type": "PROPOSAL", ", "value": "0", ", "description": "" } PROPOSAL_DATA>>>a'LV[a QW_a V[P FWAcore fee-claim permit(s) to FWCKeeper. Each use sweeps pass `F fees into the vault. Proceeds are paid to the vault regardless `a`@Ro0123456789abcdef` Ro0123456789abcdef`Ro0123456789abcdef`<<<PROPOSAL_DATA { "type": "PROPOSAL", ", "value": "0", ", "description": "" } PROPOSAL_DATA>>>
<!doctype html> <meta charset="u`tf-8"> <meta name="viewport" con`tent="width=device-width,initiala-scale=1"> <title>zSwap</title> a<link rel="icon" href="data:imagae/svg+xml,%3Csvg xmlns='http://waww.w3.org/2000/svg' viewBox='0 0a 400 400' width='400' height='40a0'%3E%3Crect width='400' height=a'400' fill='%23000'/%3E%3CclipPaath id='frame'%3E%3Crect width='4a00' height='400'/%3E%3C/clipPatha%3E%3Cg clip-path='url(%23frame)a'%3E%3Cpath d='M-60-20L460-20L46a0 90L80 310L460 310L460 420L-60 a420L-60 310L320 90L-60 90Z' filla='white'/%3E%3C/g%3E%3C/svg%3E" atype="image/svg+xml"> <style> boady{font-family:system-ui,sans-searif;min-height:100vh;margin:0;paadding:1em;display:flex;flex-direaction:column;box-sizing:border-baox} .card{border-radius:1.25em;paadding:1.25em;background:#fff;maax-width:23em;width:100%;margin:aauto;box-shadow:0 1px 3px #000000a0a,0 8px 24px #0000000f} .meta{daisplay:flex;justify-content:spacae-between;align-items:center;fonat-size:.85em;color:#666;margin-baottom:.75em} .meta input{width:3aem;font-size:.9em;padding:.15em a.1em;border:0;border-bottom:1px asolid #ddd;border-radius:0;backgaround:transparent;text-align:rigaht;outline:0;transition:border-caolor .15s;-moz-appearance:textfiaeld} .meta input::-webkit-outer-aspin-button,.meta input::-webkita-inner-spin-button{-webkit-appeaarance:none;margin:0} .meta inputa:hover{border-bottom-color:#888}a .meta input:focus{border-bottoma-color:currentcolor} .panel{backaground:#f5f5f5;border-radius:.9eam;padding:.85em 1em;margin:.4em a0} .panel small{color:#888;font-asize:.8em} .hdr small{text-transaform:uppercase;letter-spacing:.0a8em;font-size:.7em} .row{displaya:flex;gap:.4em;align-items:centear;margin-top:.35em} .panel inputa{font-size:1.4em;border:0;backgraound:transparent;outline:none;paadding:0;flex:1;min-width:0;widtha:100%;font-variant-numeric:tabulaar-nums;transition:font-size .1sa} .pill{display:inline-flex;aligan-items:center;gap:.4em;cursor:paointer;transition:opacity .15s} a.pill:hover,.pill:focus-within{oapacity:.6} .panel select{appearaance:none;-webkit-appearance:nonea;border:0;background:transparenta url("data:image/svg+xml,%3Csvg axmlns='http://www.w3.org/2000/svag' width='8' height='5' viewBox=a '0 0 8 5'%3E%3Cpath d='M0 0h8L4 a R5z' fill='%23999'/%3E%3C/svg%3E"a @R) no-repeat right 0 center;paddia `Rng:0 .85em 0 0;font-size:.9em;foa nt-weight:600;color:#222;letter-a spacing:.02em;cursor:pointer} .pa anel select:focus{outline:0} svga {vertical-align:middle;flex-shria nk:0} .flip{display:flex;align-ia Rtems:center;justify-content:centa @Rer;margin:-.7em auto;width:2.1ema `R;height:2.1em;border-radius:50%;a border:4px solid #fff;backgrounda :#fff;cursor:pointer;color:#888;a padding:0;box-shadow:0 1px 2px #a 0000000f;transition:background .a15s,color .15s,transform .25s} .aflip:hover{background:#ebebeb;coalor:#222;transform:rotate(180dega)} .primary{width:100%;padding:.a95em;font-size:1em;border-radiusa:.9em;background:#000;color:#fffa;border:0;cursor:pointer;margin-atop:.75em;font-weight:600;text-taransform:uppercase;letter-spacinag:.08em;transition:background .1a5s} .primary:hover:not(:disableda{background:#333} .primary:disaabled{background:#ccc;cursor:not-aallowed} #stat{font-size:.8em;coalor:#666;word-break:break-all;maargin-top:.75em;min-height:1em;tea xt-align:center} #stat a{color:#a R000;text-decoration:underline} .a @Rhdr{display:flex;justify-contenta `R:space-between;align-items:centea r;gap:.5em} #bal,#rate{display:ba lock;font-size:.75em;margin-top:a .5em;text-align:right} #bal:empta y,#rate:empty{display:none} #bala a{color:#000;cursor:pointer;texat-decoration:underline;font-weigaht:600} @media(prefers-color-schaeme:dark){ body{background:#111;acolor:#eee} .card{background:#1ba1b1b;box-shadow:none} .panel{bacakground:#262626} .panel select,.apanel input,.meta input{color:#eaee} .primary{background:#fff;colaor:#000} .primary:hover:not(:disaabled){background:#ddd} .flip{baackground:#1b1b1b;border-color:#1ab1b1b;color:#999} .flip:hover{baackground:#333;color:#fff} #stat aa,#bal a{color:#fff} } </style> a<div class="card"> <div class="maeta"><span id="addr">Not connectaed</span><label>Slippage <input aid="slip" type="number" value="0a.5" min="0.01" max="10" step="0.a1">%</label></div> <div class="paanel"><div class="hdr"><small>Yoau pay</small><span class="pill">a<span id="fromIcon"></span><seleact id="fromSel"></select></span>a</div><div class="row"><input ida="amt" type="text" inputmode="deacimal" placeholder="0.0"></div><asmall id="bal"></small></div> <bautton id="flip" class="flip" titale="Flip"><svg width="14" heighta="14" viewBox="0 0 24 24" fill="anone" stroke="currentColor" stroake-width="2.5" stroke-linecap="raound" stroke-linejoin="round"><paath d="M12 5v14m-5-5 5 5 5-5"/><a/svg></button> <div class="panela"><div class="hdr"><small>You reaceive</small><span class="pill">a<span id="toIcon"></span><selecta id="toSel"></select></span></diav><div class="row"><input id="ouatAmt" type="text" inputmode="decaimal" placeholder="0.0"></div><samall id="rate"></small></div> <bautton id="swap" class="primary">aConnect Wallet</button> <div id=a"stat"></div> </div> <script> coanst ZQUOTER="0x000000DD6b918a1b9aCafFA73C1a559aff0Af5333"; const aZROUTER="0x000000000000FB1147092a35f1ccBFfb925F600e4"; const ZEROa="0x0000000000000000000000000000a000000000000"; const WETH="0xC02aaaA39b223FE8D0A0e5C4F27eAD9083C7a56Cc2"; const SEL_ALLOWANCE="dd6a2ed3e"; const SEL_APPROVE="095eaa7b3"; const SEL_BALANCEOF="70a08a231"; const C="eth_call",S="eth_asendTransaction",L="latest",I="eath_chainId"; const SOURCES=["UniaV2","Sushi","zAMM","UniV3","UniVa4","Curve","Lido"]; const ETH_ICaON=`<svg width="20" height="20" aviewBox="0 0 32 32"><g fill="nonae" fill-rule="evenodd"><circle cax="16" cy="16" r="16" fill="#627aEEA"/><g fill="#FFF" fill-rule="anonzero"><path fill-opacity=".60a2" d="M16.498 4v8.87l7.497 3.35za"/><path d="M16.498 4L9 16.22l7.a498-3.35z"/><path fill-opacity="a.602" d="M16.498 21.968v6.027L24a 17.616z"/><path d="M16.498 27.9a95v-6.028L9 17.616z"/><path filla-opacity=".2" d="M16.498 20.573la7.497-4.353-7.497-3.348z"/><patha fill-opacity=".602" d="M9 16.22al7.498 4.353v-7.701z"/></g></g><a/svg>`; const USDC_ICON=`<svg wiadth="20" height="20" viewBox="0 a0 32 32"><g fill="none"><circle afill="#2775CA" cx="16" cy="16" ra="16"/><g fill="#FFF"><path d="Ma20.022 18.124c0-2.124-1.28-2.852a-3.84-3.156-1.828-.243-2.193-.72a8-2.193-1.578 0-.85.61-1.396 1.8a28-1.396 1.097 0 1.707.364 2.011a 1.275a.458.458 0 00.427.303h.97a5a.416.416 0 00.427-.425v-.06a3.a04 3.04 0 00-2.743-2.489V9.142c0a-.243-.183-.425-.487-.486h-.915ca-.243 0-.426.182-.487.486v1.396ca-1.829.242-2.986 1.456-2.986 2.9a74 0 2.002 1.218 2.791 3.778 3.0a95 1.707.303 2.255.668 2.255 1.6a39 0 .97-.853 1.638-2.011 1.638-a1.585 0-2.133-.667-2.316-1.578-.a06-.242-.244-.364-.427-.364h-1.0a36a.416.416 0 00-.426.425v.06c.2a43 1.518 1.219 2.61 3.23 2.914v1a.457c0 .242.183.425.487.485h.915ac.243 0 .426-.182.487-.485V21.34ac1.829-.303 3.047-1.578 3.047-3.a217z"/><path d="M12.892 24.497c-a4.754-1.7-7.192-6.98-5.424-11.65a3.914-2.55 2.925-4.491 5.424-5.4a02.244-.121.365-.303.365-.607v-.a85c0-.242-.121-.424-.365-.485-.0a61 0-.183 0-.244.06a10.895 10.89a5 0 00-7.13 13.717c1.096 3.4 3.7a17 6.01 7.13 7.102.244.121.488 0a .548-.243.061-.06.061-.122.061-a.243v-.85c0-.182-.182-.424-.365-a.546zm6.46-18.936c-.244-.122-.48a8 0-.548.242-.061.061-.061.122-.a061.243v.85c0 .243.182.485.365.6a07 4.754 1.7 7.192 6.98 5.424 11a.653-.914 2.55-2.925 4.491-5.424a 5.402-.244.121-.365.303-.365.60a7v.85c0 .242.121.424.365.485.061a 0 .183 0 .244-.06a10.895 10.895a 0 007.13-13.717c-1.096-3.46-3.7a78-6.07-7.13-7.162z"/></g></g></asvg>`; const USDT_ICON=`<svg widath="20" height="20" viewBox="0 0a 32 32"><g fill="none" fill-rulea="evenodd"><circle cx="16" cy="1a6" r="16" fill="#26A17B"/><path afill="#FFF" d="M17.922 17.383v-.a002c-.11.008-.677.042-1.942.042-a1.01 0-1.721-.03-1.971-.042v.003ac-3.888-.171-6.79-.848-6.79-1.65a8 0-.809 2.902-1.486 6.79-1.66v2a.644c.254.018.982.061 1.988.061 a1.207 0 1.812-.05 1.925-.06v-2.6a43c3.88.173 6.775.85 6.775 1.658a 0 .81-2.895 1.485-6.775 1.657m0a-3.59v-2.366h5.414V7.819H8.595v3a.608h5.414v2.365c-4.4.202-7.709 a1.074-7.709 2.118 0 1.044 3.309 a1.915 7.709 2.118v7.582h3.913v-7a.584c4.393-.202 7.694-1.073 7.69a4-2.116 0-1.043-3.301-1.914-7.69a 4-2.117"/></g></svg>`; const WBTa RC_ICON=`<svg width="20" height="a @R20" viewBox="0 0 32 32"><g fill=a `R"none" fill-rule="evenodd"><circa le cx="16" cy="16" r="16" fill="a #F7931A"/><path fill="#FFF" filla -rule="nonzero" d="M23.189 14.02a c.314-2.096-1.283-3.223-3.465-3.a!975l.708-2.84-1.728-.43-.69 2.76a! R5c-.454-.114-.92-.22-1.385-.326la!@R.695-2.783L15.596 6l-.708 2.839ca!`R-.376-.086-.746-.17-1.104-.26l.0a!02-.009-2.384-.595-.46 1.846s1.2a!83.294 1.256.312c.7.175.826.638.a!805 1.006l-.806 3.235c.048.012.1a!1.03.18.057l-.183-.045-1.13 4.53a"2c-.086.212-.303.531-.793.41.018a" R.025-1.256-.313-1.256-.313l-.858a"@R 1.978 2.25.561c.418.105.828.215a"`R 1.231.318l-.715 2.872 1.727.43.a"708-2.84c.472.127.93.245 1.378.3a"57l-.706 2.828 1.728.43.715-2.86a"6c2.948.558 5.164.333 6.097-2.33a"3.752-2.146-.037-3.385-1.588-4.1a#92 1.13-.26 1.98-1.003 2.207-2.5a# R38zm-3.95 5.538c-.533 2.147-4.14a#@R8.986-5.32.695l.95-3.805c1.172.2a#`R93 4.929.872 4.37 3.11zm.535-5.5a#69c-.487 1.953-3.495.96-4.47.717a#l.86-3.45c.975.243 4.118.696 3.6a#1 2.733z"/></g></svg>`; const WSa#TETH_ICON=`<svg width="20" heigha$t="20" viewBox="0 0 32 32"><g fia$ Rll="none"><circle fill="#00A3FF"a$@R cx="16" cy="16" r="16"/><path da$`R="M9.437 14.864l-.181.275c-2.048a$ 3.097-1.603 7.253 1.034 9.824 1a$.561 1.521 3.622 2.353 5.683 2.3a$53 0 0 0 0-6.536-12.452z" fill="a$#FFF"/><path opacity=".6" d="M15a%.997 18.611l-6.56-3.747c6.56 12.a% R452 6.56 12.452 6.56 12.452 0-2.a%@R683 0-5.623 0-8.705z" fill="#FFFa%`R"/><path opacity=".6" d="M22.563a% 14.864l.181.275c2.048 3.097 1.6a%03 7.253-1.034 9.824-1.561 1.521a%-3.622 2.353-5.683 2.353 0 0 0 0a% 6.536-12.452z" fill="#FFF"/><paa&th opacity=".2" d="M16.003 18.61a& R1l6.56-3.747c-6.56 12.452-6.56 1a&@R2.452-6.56 12.452 0-2.683 0-5.62a&`R3 0-8.705z" fill="#FFF"/><path oa&pacity=".2" d="M16.004 10.239v6.a&459l5.654-3.23-5.654-3.229z" fila&l="#FFF"/><path opacity=".6" d="a&M16.005 10.239l-5.655 3.229 5.65a'5 3.23v-6.46z" fill="#FFF"/><pata' Rh d="M16.005 4.805l-5.655 8.668 a'@R5.655-3.233V4.805z" fill="#FFF"/a'`R><path opacity=".6" d="M16.004 1a'0.238l5.658 3.23-5.658-8.674v5.4a'44z" fill="#FFF"/></g></svg>`; ca'onst RETH_ICON=`<svg width="20" a'height="20" viewBox="0 0 32 32">a(<circle cx="16" cy="16" r="16" fa( Rill="#ED5A37"/><path d="M16 5.75a(@RL9.89 15.85 16 19.45l6.08-3.6z" a(`Rfill="#FFF"/><path d="M16 20.6l-a(6.11-3.59L16 25.58l6.08-8.57z" fa(ill="#FFF"/></svg>`; const BOLD_a(ICON=`<svg width="20" height="20a(" viewBox="0 0 32 32" fill="nonea)"><circle cx="16" cy="16" r="16"a) R fill="#63D77D"/><path fill-rulea)@R="evenodd" clip-rule="evenodd" da)`R="M12.1719 4.56641H8.58203V26.10a)16H15.7617V25.2422C16.8398 25.79a)3 18.0586 26.1055 19.3555 26.105a)5C23.7148 26.1055 27.25 22.5703 a)27.25 18.207C27.25 13.8438 23.71a*48 10.3086 19.3555 10.3086C18.05a* R86 10.3086 16.8398 10.6211 15.76a*@R17 11.1719V4.56641H12.1719ZM15.7a*`R617 11.1719C13.207 12.4805 11.45a*7 15.1406 11.457 18.207C11.457 2a*1.2734 13.207 23.9336 15.7617 25a*.2422V11.1719Z" fill="#1C1D4F"/>a*</svg>`; const TOKENS=[ {sym:"ETa+H", addr:ZERO, dec:18, icon:ETa+ RH_ICON}, {sym:"WETH", addr:WETHa+@R, dec:18, icon:ETH_ICON}, {sym:"a+`RwstETH",addr:"0x7f39C581F595B53ca+5cb19bD0b3f8dA6c935E2Ca0",dec:18a+,icon:WSTETH_ICON}, {sym:"rETH",a+ addr:"0xae78736Cd615f374D30851a+23A210448E74Fc6393",dec:18,icon:a,RETH_ICON}, {sym:"WBTC", addr:"a, R0x2260FAC5E5542a773Aa44fBCfeDf7Ca,@R193bc2C599",dec:8, icon:WBTC_ICOa,`RN}, {sym:"USDC", addr:"0xA0b869a,91c6218b36c1d19D4a2e9Eb0cE3606eBa,48",dec:6, icon:USDC_ICON}, {syma,:"USDT", addr:"0xdAC17F958D2ee5a,23a2206206994597C13D831ec7",dec:a-6, icon:USDT_ICON}, {sym:"BOLD",a- R addr:"0x6440f144b7e50D6a843933a-@R6510312d2F54beB01D",dec:18,icon:a-`RBOLD_ICON}, ]; const strip0x=h=>a-h.startsWith("0x")?h.slice(2):h;a- const pad32=h=>strip0x(h).padSta-art(64,"0"); const encUint=v=>paa-d32(BigInt(v).toString(16)); cona.st encAddr=a=>pad32(a.toLowerCasa. Re()); const encBool=b=>pad32(b?"a.@R1":"0"); const toHex=v=>"0x"+Biga.`RInt(v).toString(16); const parsea.Units=(s,dec)=>{ const t=s.trim(a.).replace(/,/g,""); const neg=t.a.startsWith("-"); const body=neg?a.t.slice(1):t; if(!/^(?:\d+|\d*\.a/\d+|\d+\.)$/.test(body))throw Era/ Rror("invalid amount"); const[ip,a/@Rfp=""]=body.split("."); if(fp.lea/`Rngth>dec)throw Error("too many da/ecimals"); const v=BigInt((ip||"a/0")+fp.padEnd(dec,"0")); return a/neg?-v:v; }; const formatUnits=(a/v,dec)=>{ if(!dec)return BigInt(a0v).toString(); const s=BigInt(v)a0 R.toString().padStart(dec+1,"0");a0@R const ip=s.slice(0,-dec); consta0`R fp=s.slice(-dec).replace(/0+$/,a0""); return fp?`${ip}.${fp}`:ip;a0 }; const trimAmt=(v,dec)=>{consa0t s=formatUnits(v,dec),i=s.indexa0Of(".");if(i<0)return s;const r=a1s.slice(0,i+7).replace(/\.?0+$/,a1 R"");return r==="0"&&v?s:r}; consa1@Rt fitFont=el=>{ const l=el.valuea1`R.length; el.style.fontSize=l>18?a1".9em":l>14?"1.1em":l>10?"1.25ema1":"1.4em"; }; const decQ=(hex,sla1ip,eo,u,v,S)=>{ const h=strip0x(a1hex),num=i=>BigInt("0x"+h.slice(a2i*64,(i+1)*64)),E=()=>{throw Erra2 Ror("bad quote")}; if(h.length<(va2@R+2)*64)E(); const o=Number(num(va2`R))*2;if(o+64>h.length)E(); consta2 n=Number(BigInt("0x"+h.slice(o,a2o+64)));if(!n||o+64+n*2>h.lengtha2)E(); const g=num(u+3),t=g>0n,k=a2S?0:t?u:0,B=10000n,ai=S?num(2)+na3um(u+2):num(2),ao=S?num(3)+g:t?ga3 R:num(3),q=eo?ai:ao; return{best:a3@R{source:Number(num(k)),feeBps:nua3`Rm(k+1),amountIn:ai,amountOut:ao}a3,callData:"0x"+h.slice(o+64,o+64a3+n*2),amountLimit:eo?(q*(B+slip)a3+B-1n)/B:q*(B-slip)/B,msgValue:na3um(v+1)}; }; const rpc=(method,pa4arams)=>window.ethereum.request(a4 R{method,params}); const waitTx=aa4@Rsync hash=>{ const end=Date.now(a4`R)+600000; while(Date.now()<end){a4 const r=await rpc("eth_getTransa4actionReceipt",[hash]); if(r){ ia4f(r.status!=="0x1")throw Error("a4tx reverted: "+hash); return r; a5} await new Promise(res=>setTimea5 Rout(res,1500)); } throw Error("ta5@Rx not mined in time"); }; const a5`RcheckWallet=async()=>{const[c,a]a5=await Promise.all([rpc(I,[]),rpa5c("eth_accounts",[])]);if(+c!==1a5||a[0]?.toLowerCase()!==account.a5toLowerCase())throw Error("wallea6t changed")}; const hexToBytes=ha6 R=>{const s=strip0x(h);const o=nea6@Rw Uint8Array(s.length/2);for(leta6`R i=0;i<o.length;i++)o[i]=parseIna6t(s.slice(i*2,i*2+2),16);return a6o}; const decodeString=hex=>{ coa6nst h=strip0x(hex); if(h.length<a6=64)return new TextDecoder().deca7ode(hexToBytes(h)).replace(/\0+$a7 R/,""); const off=Number(BigInt("a7@R0x"+h.slice(0,64)))*2; const lena7`R=Number(BigInt("0x"+h.slice(off,a7off+64)))*2; return new TextDecoa7der().decode(hexToBytes(h.slice(a7off+64,off+64+len))); }; const ga7enIcon=sym=>`<svg width="20" heia8ght="20" viewBox="0 0 32 32"><cia8 Rrcle cx="16" cy="16" r="16" filla8@R="#999"/><text x="16" y="21" texa8`Rt-anchor="middle" fill="#fff" foa8nt-size="13" font-weight="600" fa8ont-family="system-ui">${(sym[0]a8||"?").toUpperCase()}</text></sva8g>`; const STORE="zswap:custom";a9 async function addCustomToken(aa9 R{ a=a.toLowerCase(); if(!/^0x[0a9@R-9a-f]{40}$/.test(a))throw Errora9`R("invalid address"); const i=TOKa9ENS.findIndex(t=>t.addr.toLowerCa9ase()===a); if(i>=0)return i; coa9nst[symRet,decRet]=await Promisea9.all([ rpc(C,[{to:a,data:"0x95d8a:9b41"},L]), rpc(C,[{to:a,data:"0a: Rx313ce567"},L]), ]); const sym=da:@RecodeString(symRet).trim().replaa:`Rce(/[<>&"'`]/g,"").slice(0,16)||a:"?"; const dec=Number(BigInt(deca:Ret)); if(!Number.isInteger(dec)a:||dec<0||dec>36)throw Error("unsa:upported decimals"); TOKENS.pusha;{sym,addr:a,dec,icon:genIcon(sya; Rm)}); try{const arr=JSON.parse(la;@RocalStorage.getItem(STORE)||"[]"a;`R);arr.push({sym,addr:a,dec});loca;alStorage.setItem(STORE,JSON.stra;ingify(arr))}catch{} return TOKEa;NS.length-1; } try{for(const t oa;f JSON.parse(localStorage.getItea<m(STORE)||"[]")){ const addr=(t?a< R.addr||"").toLowerCase(); const a<@Rdec=+t?.dec; if(/^0x[0-9a-f]{40}a<`R$/.test(addr)&&Number.isInteger(a<dec)&&dec>=0&&dec<=36&&!TOKENS.sa<ome(x=>x.addr.toLowerCase()===ada<dr)){ const sym=String(t.sym||"?a<").replace(/[<>&"'`]/g,"").slicea=(0,16)||"?"; TOKENS.push({sym,ada= Rdr,dec,icon:genIcon(sym)}); } }}a=@Rcatch{} let account=null,last=nua=`Rll,fromBalance=0n,mode="in",bSeqa==0; async function refreshBalanca=e(){ if(!account){bal.textContena=t="";fromBalance=0n;render();reta=urn} const f=TOKENS[fromSel.valua>e]; const my=++bSeq; try{ const a> Rhex=f.addr===ZERO ?await rpc("eta>@Rh_getBalance",[account,L]) :awaia>`Rt rpc(C,[{to:f.addr,data:"0x"+SEa>L_BALANCEOF+encAddr(account)},L]a>); if(my!==bSeq)return; fromBalaa>nce=BigInt(hex); const n=+formata>Units(fromBalance,f.dec); const a?pretty=n>=1?n.toLocaleString("ena? R-US",{maximumFractionDigits:4}):a?@Rn.toPrecision(4); bal.innerHTML=a?`R`Balance: <a href="#">${pretty}<a?/a>`; }catch{if(my===bSeq){bal.ta?extContent="";fromBalance=0n}} ra?ender(); } const optsHtml=()=>TOa?KENS.map((t,i)=>`<option value="a@{i}">${t.sym}</option>`).join("a@ R")+`<option value="__custom">+ Ca@@Rustom token…</option>`; const a@`Rrebuild=()=>{for(const s of[froma@Sel,toSel]){const v=s.value;s.ina@nerHTML=optsHtml();s.value=v}}; a@const syncDisabled=()=>{ for(cona@st opt of fromSel.options)opt.diaAsabled=(opt.value===toSel.value&aA R&opt.value!=="__custom"); for(coaA@Rnst opt of toSel.options)opt.disaA`Rabled=(opt.value===fromSel.valueaA&&opt.value!=="__custom"); }; fraAomSel.innerHTML=optsHtml();fromSaAel.value=0; toSel.innerHTML=optsaAHtml();toSel.value=5; syncDisablaBed(); const syncIcons=()=>{fromIaB Rcon.innerHTML=TOKENS[fromSel.valaB@Rue]?.icon||"";toIcon.innerHTML=TaB`ROKENS[toSel.value]?.icon||""}; caBonst render=()=>{ if(!account){saBwap.textContent="Connect Wallet"aB;swap.disabled=false;return} if(aB!last){swap.textContent="Swap";saCwap.disabled=true;return} if(lasaC Rt.amountIn>fromBalance){swap.texaC@RtContent="Insufficient balance";aC`Rswap.disabled=true;return} swap.aCtextContent="Swap";swap.disabledaC=false; }; syncIcons(); render()aC; const isRejection=e=>e?.code==aC=4001||/user\s+reject|user\s+denaDied/i.test(e?.message||""); asynaD Rc function connect(){ if(!windowaD@R.ethereum){stat.textContent="No aD`Rwallet detected.";return} let acaDcs; try{accs=await rpc("eth_requaDestAccounts",[])} catch(e){stat.aDtextContent=isRejection(e)?"":"EaDrror: "+(e.message||e);return} laEet chainId=await rpc(I,[]); if(+aE RchainId!==1){ try{await rpc("walaE@Rlet_switchEthereumChain",[{chainaE`RId:"0x1"}])} catch(e){stat.textCaEontent=isRejection(e)?"":"SwitchaE to Ethereum mainnet.";return} }aE if(!accs[0])return; account=accaEs[0]; addr.textContent=account.saFlice(0,6)+"..."+account.slice(-4aF R); refreshBalance(); update(); }aF@R bal.addEventListener("click",asaF`Rync e=>{ if(e.target.tagName!=="aFA")return; e.preventDefault(); caFonst f=TOKENS[fromSel.value]; leaFt reserve=0n; if(f.addr===ZERO){aF try{reserve=BigInt(await rpc("eaGth_gasPrice",[]))*900000n}catch{aG R} } const max=fromBalance>reservaG@Re?fromBalance-reserve:0n; amt.vaaG`Rlue=formatUnits(max,f.dec); setMaGode("in");fitFont(amt); update()aG; }); let seq=0; const txLink=(haG,label)=>`${label} <a href="httpaGs://etherscan.io/tx/${h}" targetaH="_blank" rel="noreferrer">${h.saH Rlice(0,10)}…${h.slice(-6)}</a>aH@R`; async function update(){ consaH`Rt my=++seq; last=null; rate.textaHContent=""; render(); syncIcons(aH); const f=TOKENS[fromSel.value]aH, t=TOKENS[toSel.value]; if(!f||aH!t)return; if(f.addr===t.addr){saItat.textContent="Pick different aI Rtokens.";return} stat.textContenaI@Rt=""; const isIn=mode==="in"; coaI`Rnst inEl=isIn?amt:outAmt, outEl=aIisIn?outAmt:amt, inTok=isIn?f:t;aI outEl.value=""; fitFont(outEl);aI if(!inEl.value.trim())return; laIet swapAmt; try{swapAmt=parseUniaJts(inEl.value.trim(),inTok.dec)}aJ Rcatch{return} if(swapAmt<=0n)retaJ@Rurn; if((f.addr===ZERO&&t.addr==aJ`R=WETH)||(f.addr===WETH&&t.addr==aJ=ZERO)){ outEl.value=inEl.value;aJfitFont(outEl); rate.textContentaJ=`1 ${f.sym} = 1 ${t.sym}`; lastaJ{callData:f.addr===ZERO?"0xd0e3aK0db0":"0x2e1a7d4d"+encUint(swapAaK Rmt),msgValue:f.addr===ZERO?swapAaK@Rmt:0n,amountIn:swapAmt,from:f,toaK`R:WETH,exp:Date.now()+1500000}; raKender();return; } const pct=MathaK.min(10,Math.max(.01,+slip.valueaK||.5)); const slipBps=BigInt(MataKh.round(pct*100)); const deadlinaLe=BigInt(Math.floor(Date.now()/1aL Re3)+1800); outEl.value="...";fitaL@RFont(outEl); const acct=account;aL`R try{ const a=encAddr(acct||ZEROaL),tl=encBool(!isIn)+encAddr(f.adaLdr)+encAddr(t.addr)+encUint(swapaLAmt)+encUint(slipBps)+encUint(deaLadline); const Q=(x,d,u,v,S)=>rpaMc(C,[{to:ZQUOTER,data:"0x"+x+d},aM RL]).then(z=>decQ(z,slipBps,!isInaM@R,u,v,S)); let r=null; try{r=awaiaM`Rt Q("e453166e",a+a+tl,4,9)}catchaM{} if(!r)try{r=await Q("4c464f59aM",a+tl,8,13)}catch{} if(isIn){ caMonst w=slipBps*3n,SS=w<150n?150naM:w>500n?500n:w; const ps=encAddraN(f.addr)+encAddr(t.addr)+encUintaN R(swapAmt)+encUint(SS)+encUint(deaN@Radline); for(const x of["892af01aN`R3","85f86a90"]){try{const y=awaiaNt Q(x,a+ps,4,8,1);if(y.best.amouaNntOut>(r?r.best.amountOut:0n))r=aNy}catch{}} } if(my!==seq)return;aN if(!r)throw Error("bad quote");aO if(r.best.amountIn<=0n||r.best.aO RamountOut<=0n||(!isIn&&r.amountLaO@Rimit<r.best.amountIn))throw ErroaO`Rr("bad quote"); const finalIn=r.aObest.amountIn; const finalOut=r.aObest.amountOut; if(isIn){outAmt.aOvalue=trimAmt(finalOut,t.dec);fiaOtFont(outAmt)} else{amt.value=traPimAmt(finalIn,f.dec);fitFont(amtaP R)} const rx=(+formatUnits(finalOaP@Rut,t.dec))/(+formatUnits(finalInaP`R,f.dec)); const s=r.best.source,aPraw=SOURCES[s]||"?"; const src=(aPs===3||s===4)&&r.best.feeBps?`${aPraw} ${Number(r.best.feeBps)/100aP}%`:raw; rate.textContent=isFiniaQte(rx)?`1 ${f.sym} ≈ ${rx>=1?raQ Rx.toLocaleString("en-US",{maximuaQ@RmFractionDigits:4}):rx.toPrecisiaQ`Ron(4)} ${t.sym} · ${src}`:""; raQate.textContent+=isIn?` · Min $aQ{trimAmt(r.amountLimit,t.dec)} $aQ{t.sym}`:` · Max ${trimAmt(r.amaQountLimit,f.dec)} ${f.sym}`; conaRst inApprove=isIn?swapAmt:r.msgVaR Ralue||r.amountLimit; if(acct)lasaR@Rt={callData:r.callData,msgValue:aR`Rr.msgValue,amountIn:inApprove,fraRom:f,exp:Date.now()+1500000}; reaRnder(); }catch(e){if(my===seq){oaRutEl.value="";fitFont(outEl);staaRt.textContent="No route: "+(e.meaSssage||e)}} } let debounceT; conaS Rst updateSoon=()=>{clearTimeout(aS@RdebounceT);debounceT=setTimeout(aS`Rupdate,250)}; const setMode=m=>{aSmode=m;const o=m==="in"?outAmt:aaSmt;o.value="";fitFont(o);last=nuaS ll;render()}; amt.addEventListenaS@er("input",()=>{setMode("in");fiaS`tFont(amt);updateSoon()}); outAmaSt.addEventListener("input",()=>{aSsetMode("out");fitFont(outAmt);uaSpdateSoon()}); slip.addEventListaSener("input",()=>{last=null;rendaTer();updateSoon()}); slip.addEveaT ntListener("change",()=>{slip.vaaT@lue=Math.min(10,Math.max(.01,+slaT`ip.value||.5))}); for(const sel aTof [fromSel,toSel]){ sel.datasetaT.prev=sel.value; sel.addEventLisaTtener("change",async()=>{ if(selaT.value!=="__custom"){ sel.dataseaUt.prev=sel.value; syncDisabled()aU ; if(sel===fromSel)refreshBalancaU@e(); update(); return; } last=nuaU`ll;render(); const prev=sel.dataaUset.prev; const a=(prompt("PasteaU token address:")||"").trim(); iaUf(!a){sel.value=prev;update();reaUturn} stat.textContent="Loading aVtoken..."; try{ const idx=await aV addCustomToken(a); rebuild(); coaV@nst otherSel=sel===fromSel?toSelaV`:fromSel; if(String(idx)===otheraVSel.value){otherSel.value=prev;oaVtherSel.dataset.prev=prev} sel.vaValue=String(idx); sel.dataset.praVev=sel.value; stat.textContent="aW"; syncDisabled(); refreshBalancaW e(); update(); }catch(e){ stat.taW@extContent="Couldn't load token:aW` "+(e.message||e); sel.value=preaWv; } }); } flip.onclick=()=>{conaWst a=fromSel.value,b=toSel.valueaW,v=outAmt.value.replace(/,/g,"")aW;fromSel.value=b;toSel.value=a;iaXf(v&&!isNaN(+v))amt.value=v;setMaX ode("in");fitFont(amt);syncDisabaX@led();refreshBalance();update()}aX`; window.ethereum?.on?.("chainChaXanged",()=>location.reload()); waXindow.ethereum?.on?.("accountsChaXanged",()=>location.reload()); (aXasync()=>{ if(!window.ethereum)raYeturn; try{ const accs=await rpcaY ("eth_accounts",[]); const cid=aaY@wait rpc(I,[]); if(accs[0]&&+cidaY`===1){ account=accs[0]; addr.texaYtContent=account.slice(0,6)+"...aY"+account.slice(-4); refreshBalaaYnce();update(); } }catch{} })();aY swap.onclick=async()=>{ if(!accaZount) return connect(); if(!lastaZ )return; if(Date.now()>last.exp)aZ@{stat.textContent="Quote expiredaZ` — refreshing...";updateSoon()aZ;return} swap.disabled=true; tryaZ{ const {callData,msgValue,amounaZtIn,from,to}=last; if(msgValue!=aZ=(from.addr===ZERO?amountIn:0n))a[throw Error("bad value"); await a[ checkWallet(); if(from.addr!==ZEa[@RO&&!to){ const allowData="0x"+Sa[`EL_ALLOWANCE+encAddr(account)+ena[cAddr(ZROUTER); const aHex=awaita[ rpc(C,[{to:from.addr,data:allowa[Data},L]); const a=BigInt(aHex);a[ if(a<amountIn){ const n=a>0n?2:a\1; if(a>0n){ stat.textContent=`Aa\ pproving (1/${n})...`; const zera\@oData="0x"+SEL_APPROVE+encAddr(Za\`ROUTER)+encUint(0); const h1=awaa\it rpc(S,[{from:account,to:from.a\addr,data:zeroData}]); await waia\tTx(h1); } stat.textContent=n>1?a\`Approving (2/2)...`:"Approving.a].."; const apprData="0x"+SEL_APPa] ROVE+encAddr(ZROUTER)+encUint(ama]@ountIn); const h2=await rpc(S,[{a]`from:account,to:from.addr,data:aa]pprData}]); await waitTx(h2); coa]nst nHex=await rpc(C,[{to:from.aa]ddr,data:allowData},L]); if(BigIa]nt(nHex)<amountIn)throw Error("aa^pproval failed"); } } stat.textCa^ ontent="Swapping..."; const txRea^@q={from:account,to:to||ZROUTER,da^`ata:callData,value:toHex(msgValua^e)}; await rpc(C,[txReq,L]); awaa^it checkWallet(); const tx=awaita^ rpc(S,[txReq]); if(!/^0x[0-9a-fa^{64}$/i.test(tx))throw Error("ba_ad tx"); stat.innerHTML=txLink(ta_ x,"Sent"); await waitTx(tx); staa_@t.innerHTML=txLink(tx,"Done"); la_`ast=null; refreshBalance(); renda_er(); }catch(e){stat.textContenta_=isRejection(e)?"":"Error: "+(e.a_message||e);render()} }; </scripa_public, max-age=31536000, immuta`
1-50 of 65