Walrus blob · mainnet
On-chain registration not yet visible.
The aggregator served this blob, but we couldn't locate a matching BlobRegistered event in our scan window. It may not be certified yet, or live further back than we paged.
Lifecycle data is unavailable until the blob registration is visible on-chain.
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>RendySui — Stake on every Sui validator</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,600;12..96,800&family=Manrope:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"><style>:root{--bg:#03101e;--bg-2:#061a2e;--ink:#eaf4ff;--ink-soft:#9cb6cf;--aqua:#4da2ff;--aqua-bright:#6fbcf0;--mint:#7af2d1;--warn:#ffcf6f;--bad:#ff8a8a;--line:rgba(111,188,240,.14);--card:rgba(13,38,62,.55);--display:"Bricolage Grotesque",serif;--body:"Manrope",sans-serif;--mono:"JetBrains Mono",monospace}*{margin:0;padding:0;box-sizing:border-box}html{scroll-behavior:smooth}body{background:var(--bg);color:var(--ink);font-family:var(--body);line-height:1.55;-webkit-font-smoothing:antialiased;min-height:100vh}.bg-mesh{position:fixed;inset:0;z-index:-1;background:radial-gradient(55% 45% at 82% 4%,rgba(77,162,255,.20),transparent 60%),radial-gradient(45% 40% at 8% 14%,rgba(122,242,209,.09),transparent 60%),linear-gradient(180deg,#03101e,#020b15 80%,#03101e)}.wrap{max-width:1080px;margin:0 auto;padding:0 22px}a{color:var(--aqua-bright)}nav{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 22px;max-width:1080px;margin:0 auto;flex-wrap:wrap}.brand{display:flex;align-items:center;gap:10px;font-family:var(--display);font-weight:800;font-size:19px;letter-spacing:-.02em}.logo{width:30px;height:30px;border-radius:9px;background:linear-gradient(135deg,var(--aqua),var(--mint));display:grid;place-items:center;color:#03101e;font-weight:800;font-family:var(--display)}.nav-right{display:flex;align-items:center;gap:10px}.navlink{font-size:14px;font-weight:600;color:var(--ink-soft);text-decoration:none;padding:9px 12px;border-radius:9px;transition:.2s}.navlink:hover,.navlink.active{color:var(--ink);background:rgba(77,162,255,.08)}.net-toggle{display:flex;border:1px solid var(--line);border-radius:10px;overflow:hidden;font-family:var(--mono);font-size:12px}.net-toggle button{background:transparent;color:var(--ink-soft);border:none;padding:8px 12px;cursor:pointer;transition:.2s}.net-toggle button.active{background:rgba(77,162,255,.18);color:var(--ink)}.btn{font-family:var(--body);font-weight:700;font-size:14px;padding:11px 18px;border-radius:11px;border:1px solid transparent;cursor:pointer;transition:.2s;display:inline-flex;align-items:center;gap:8px}.btn-primary{background:linear-gradient(135deg,var(--aqua),var(--aqua-bright));color:#03101e}.btn-primary:hover{filter:brightness(1.06)}.btn-primary:disabled{opacity:.45;cursor:not-allowed;filter:none}.btn-ghost{border-color:var(--line);color:var(--ink);background:transparent}.btn-ghost:hover{border-color:var(--aqua);background:rgba(77,162,255,.08)}.addr{font-family:var(--mono);font-size:12.5px;color:var(--aqua-bright);border:1px solid var(--line);border-radius:10px;padding:9px 13px;display:flex;align-items:center;gap:8px}.addr .x{color:var(--ink-soft);cursor:pointer}header{padding:34px 0 18px}h1{font-family:var(--display);font-weight:800;font-size:clamp(32px,5.4vw,52px);line-height:1.02;letter-spacing:-.03em;max-width:18ch}h1 .em{background:linear-gradient(120deg,var(--aqua-bright),var(--mint));-webkit-background-clip:text;background-clip:text;color:transparent}.lede{margin-top:14px;color:var(--ink-soft);font-size:16.5px;max-width:60ch}.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;margin-top:26px;border:1px solid var(--line);border-radius:16px;overflow:hidden;background:var(--line)}.stat{background:var(--bg-2);padding:18px 18px}.stat .n{font-family:var(--display);font-weight:800;font-size:24px;letter-spacing:-.02em}.stat .l{font-size:12px;color:var(--ink-soft);margin-top:2px}@media(max-width:680px){.stats{grid-template-columns:repeat(2,1fr)}}.notice{margin:22px 0 0;border:1px solid rgba(255,207,111,.3);background:rgba(255,207,111,.06);border-radius:14px;padding:14px 16px;font-size:13.5px;color:var(--warn);display:flex;gap:10px}.notice.testnet{border-color:rgba(122,242,209,.3);background:rgba(122,242,209,.06);color:var(--mint)}section{padding:30px 0}h2{font-family:var(--display);font-weight:700;font-size:24px;letter-spacing:-.02em;display:flex;align-items:center;gap:10px}.tools{display:flex;gap:10px;margin:18px 0;flex-wrap:wrap}.tools input,.tools select{font-family:var(--body);font-size:14px;background:var(--bg-2);border:1px solid var(--line);color:var(--ink);border-radius:11px;padding:11px 13px}.tools input{flex:1;min-width:200px}.tools input::placeholder{color:#5d7794}.vlist{display:flex;flex-direction:column;gap:8px}.vrow{display:grid;grid-template-columns:minmax(0,1fr) auto auto auto;gap:14px;align-items:center;background:var(--card);border:1px solid var(--line);border-radius:14px;padding:14px 16px;transition:.2s}.vrow:hover{border-color:rgba(111,188,240,.32)}.vmeta{display:flex;align-items:center;gap:12px;min-width:0}.vimg{width:38px;height:38px;border-radius:50%;flex-shrink:0;background:linear-gradient(135deg,var(--aqua),var(--mint));display:grid;place-items:center;color:#03101e;font-weight:800;font-family:var(--display);font-size:15px;overflow:hidden}.vimg img{width:100%;height:100%;object-fit:cover}.vname{font-weight:600;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.vsub{font-family:var(--mono);font-size:11px;color:var(--ink-soft)}.vcol{text-align:right}.vcol .big{font-family:var(--display);font-weight:700;font-size:16px}.vcol .lab{font-size:10.5px;color:var(--ink-soft);text-transform:uppercase;letter-spacing:.06em}.vcol.apy .big{color:var(--mint)}.vstake{display:flex;gap:7px;align-items:center}.vstake input{width:84px;font-family:var(--mono);font-size:13px;background:var(--bg-2);border:1px solid var(--line);color:var(--ink);border-radius:9px;padding:9px 10px;text-align:right}.vstake .btn{padding:9px 14px;font-size:13px}@media(max-width:760px){.vrow{grid-template-columns:1fr 1fr;grid-auto-rows:auto}.vmeta{grid-column:1/3}.vstake{grid-column:1/3}.vstake input{flex:1;width:auto}}.empty{color:var(--ink-soft);font-size:14.5px;padding:24px;text-align:center;border:1px dashed var(--line);border-radius:14px}.spin{display:inline-block;width:15px;height:15px;border:2px solid rgba(255,255,255,.25);border-top-color:var(--aqua-bright);border-radius:50%;animation:sp .7s linear infinite;vertical-align:-2px}@keyframes sp{to{transform:rotate(360deg)}}#toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(120%);background:var(--bg-2);border:1px solid var(--line);border-radius:13px;padding:14px 18px;font-size:14px;max-width:90vw;box-shadow:0 18px 50px rgba(0,0,0,.5);transition:.3s;z-index:50}#toast.show{transform:translateX(-50%) translateY(0)}#toast.ok{border-color:rgba(122,242,209,.4)}#toast.err{border-color:rgba(255,138,138,.4)}#toast a{color:var(--aqua-bright)}#modal{position:fixed;inset:0;background:rgba(2,8,15,.7);backdrop-filter:blur(4px);display:none;align-items:center;justify-content:center;z-index:60;padding:20px}#modal.show{display:flex}.modal-card{background:var(--bg-2);border:1px solid var(--line);border-radius:18px;padding:24px;width:340px;max-width:100%}.modal-card h3{font-family:var(--display);font-size:19px;margin-bottom:4px}.modal-card p{color:var(--ink-soft);font-size:13px;margin-bottom:16px}.wopt{display:flex;align-items:center;gap:12px;width:100%;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:13px 14px;cursor:pointer;margin-bottom:8px;color:var(--ink);font-size:14.5px;font-weight:600}.wopt:hover{border-color:var(--aqua)}.wopt img{width:26px;height:26px;border-radius:7px}.modal-card .close{margin-top:8px;width:100%;text-align:center;color:var(--ink-soft);background:none;border:none;cursor:pointer;font-size:13px}footer{border-top:1px solid var(--line);margin-top:40px;padding:26px 0;color:var(--ink-soft);font-size:12.5px}.foot{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;align-items:center}.disc{margin-top:10px;font-size:11.5px;color:#6a83a0;max-width:80ch}</style></head><body><div class="bg-mesh"></div><nav><div class="brand"><span class="logo">R</span>RendySui</div><div class="nav-right"><a class="navlink" href="/portfolio">Portfolio →</a><div class="net-toggle" id="netToggle"><button data-net="mainnet" class="active">Mainnet</button><button data-net="testnet">Testnet</button></div><div id="walletArea"><button class="btn btn-primary" id="connectBtn">Connect Wallet</button></div></div></nav><header class="wrap"><h1>Stake SUI with <span class="em">any validator.</span></h1><p class="lede">Connect your wallet and delegate to any active validator on the Sui network. Non-custodial — your StakedSui stays in your wallet, and you can withdraw whenever you want. Rewards accrue every epoch.</p><div class="stats"><div class="stat"><div class="n" id="stEpoch">—</div><div class="l">Current epoch</div></div><div class="stat"><div class="n" id="stVals">—</div><div class="l">Active validators</div></div><div class="stat"><div class="n" id="stStaked">—</div><div class="l">Total staked (SUI)</div></div><div class="stat"><div class="n" id="stApy">—</div><div class="l">Avg APY</div></div></div><div class="notice" id="netNotice"><span>⚠</span><span><strong>Mainnet — real funds.</strong> Transactions stake real SUI. Always review the details in your wallet before approving. Minimum stake is 1 SUI.</span></div></header><section class="wrap" id="mySection" style="display:none"><h2>Your stakes</h2><div id="myStakes" style="display:flex;flex-direction:column;gap:8px"></div></section><section class="wrap"><h2>Validators <span id="valSpin"></span></h2><div class="tools"><input id="search" placeholder="Search validators by name…"><select id="sort"><option value="apy">Sort: Highest APY</option><option value="stake">Sort: Most staked</option><option value="comm">Sort: Lowest commission</option><option value="name">Sort: Name (A–Z)</option></select></div><div class="vlist" id="vlist"><div class="empty">Loading validators… <span class="spin"></span></div></div></section><footer><div class="wrap"><div class="foot"><div class="brand" style="font-size:16px"><span class="logo" style="width:24px;height:24px;font-size:12px;border-radius:7px">R</span>RendySui</div><div style="font-family:var(--mono)">rendysui.epoch · on Walrus</div></div><p class="disc">RendySui is a non-custodial interface to Sui's native delegated proof-of-stake. It never takes custody of your funds and charges no fee of its own — you pay only network gas. Staking and unstaking take effect at the next epoch boundary (~24h); withdrawing returns your principal plus accrued rewards. This software is provided as-is, without warranty; verify every transaction in your wallet. Not financial advice.</p></div></footer><div id="toast"></div><div id="modal"><div class="modal-card"><h3>Connect a wallet</h3><p>Choose a Sui wallet to continue.</p><div id="wopts"></div><button class="close" onclick="document.getElementById('modal').classList.remove('show')">Cancel</button></div></div><script type="module">import { SuiClient, getFullnodeUrl } from 'https://esm.sh/@mysten/sui@1/client';import { Transaction } from 'https://esm.sh/@mysten/sui@1/transactions';import { getWallets } from 'https://esm.sh/@mysten/wallet-standard@0';const SYS='0x5';const $=id=>document.getElementById(id);let network='mainnet';let client=new SuiClient({url:getFullnodeUrl(network)});let validators=[];let apyMap={};let wallet=null;let account=null;function fmt(n,d=0){return Number(n).toLocaleString('en-US',{maximumFractionDigits:d})}function suiFromMist(m){return Number(BigInt(m))/1e9}function short(a){return a.slice(0,6)+'…'+a.slice(-4)}function toast(msg,kind){const t=$('toast');t.className='';t.innerHTML=msg;if(kind)t.classList.add(kind);t.classList.add('show');clearTimeout(t._t);t._t=setTimeout(()=>t.classList.remove('show'),kind==='err'?9000:7000)}function explorerTx(d){const n=network==='mainnet'?'':'?network='+network;return 'https://suivision.xyz/txblock/'+d+n}function suiWallets(){return getWallets().get().filter(w=>w.features['sui:signAndExecuteTransaction']||w.features['standard:connect'])}function renderWalletArea(){const area=$('walletArea');if(account){area.innerHTML='<div class="addr">'+short(account.address)+' <span class="x" id="dcBtn" title="Disconnect">✕</span></div>';$('dcBtn').onclick=disconnect}else{area.innerHTML='<button class="btn btn-primary" id="connectBtn">Connect Wallet</button>';$('connectBtn').onclick=openModal}}function openModal(){const ws=suiWallets();const box=$('wopts');if(ws.length===0){box.innerHTML='<p style="color:var(--bad);font-size:13px">No Sui wallet detected. Install Sui Wallet, Suiet, or Slush and reload.</p>'}else{box.innerHTML='';ws.forEach((w,i)=>{const b=document.createElement('button');b.className='wopt';b.innerHTML=(w.icon?'<img src="'+w.icon+'">':'')+(w.name||('Wallet '+i));b.onclick=()=>connect(w);box.appendChild(b)})}$('modal').classList.add('show')}async function connect(w){try{await w.features['standard:connect'].connect();wallet=w;account=w.accounts[0];if(w.features['standard:events']){w.features['standard:events'].on('change',({accounts})=>{if(accounts&&accounts.length){account=accounts[0]}else{account=null}renderWalletArea();loadMyStakes()})}$('modal').classList.remove('show');renderWalletArea();toast('Wallet connected: '+short(account.address),'ok');loadMyStakes()}catch(e){toast('Connection failed: '+(e.message||e),'err')}}function disconnect(){try{wallet?.features['standard:disconnect']?.disconnect()}catch(e){}wallet=null;account=null;renderWalletArea();$('mySection').style.display='none'}async function loadSystem(){$('valSpin').innerHTML='<span class="spin"></span>';$('vlist').innerHTML='<div class="empty">Loading validators… <span class="spin"></span></div>';try{const [state,apy]=await Promise.all([client.getLatestSuiSystemState(),client.getValidatorsApy().catch(()=>({apys:[]}))]);apyMap={};(apy.apys||[]).forEach(a=>apyMap[a.address]=a.apy);validators=state.activeValidators.map(v=>({address:v.suiAddress,name:v.name||short(v.suiAddress),img:v.imageUrl||'',commission:Number(v.commissionRate)/100,stake:BigInt(v.stakingPoolSuiBalance),apy:(apyMap[v.suiAddress]??0)*100}));const totalStake=validators.reduce((s,v)=>s+v.stake,0n);const avgApy=validators.length?validators.reduce((s,v)=>s+v.apy,0)/validators.length:0;$('stEpoch').textContent=state.epoch;$('stVals').textContent=validators.length;$('stStaked').textContent=fmt(suiFromMist(totalStake));$('stApy').textContent=avgApy.toFixed(2)+'%';renderValidators()}catch(e){$('vlist').innerHTML='<div class="empty" style="color:var(--bad)">Failed to load validators: '+(e.message||e)+'</div>'}$('valSpin').innerHTML=''}function renderValidators(){const q=$('search').value.trim().toLowerCase();const sort=$('sort').value;let list=validators.filter(v=>v.name.toLowerCase().includes(q));list.sort((a,b)=>{if(sort==='apy')return b.apy-a.apy;if(sort==='stake')return a.stake<b.stake?1:-1;if(sort==='comm')return a.commission-b.commission;return a.name.localeCompare(b.name)});if(!list.length){$('vlist').innerHTML='<div class="empty">No validators match.</div>';return}const box=$('vlist');box.innerHTML='';list.forEach(v=>{const row=document.createElement('div');row.className='vrow';const initial=v.name.replace(/[^a-zA-Z0-9]/g,'').charAt(0).toUpperCase()||'V';row.innerHTML='<div class="vmeta"><div class="vimg">'+(v.img?'<img src="'+v.img+'" onerror="this.parentNode.textContent=\''+initial+'\'">':initial)+'</div><div style="min-width:0"><div class="vname">'+v.name+'</div><div class="vsub">'+short(v.address)+'</div></div></div><div class="vcol apy"><div class="big">'+v.apy.toFixed(2)+'%</div><div class="lab">APY</div></div><div class="vcol"><div class="big">'+v.commission.toFixed(1)+'%</div><div class="lab">Commission</div></div><div class="vstake"><input type="number" min="1" step="1" placeholder="SUI"><button class="btn btn-primary">Stake</button></div>';const input=row.querySelector('input');const btn=row.querySelector('button');btn.onclick=()=>stake(v.address,input.value,btn);box.appendChild(row)})}async function stake(validator,amountStr,btn){if(!account){openModal();return}const amount=parseFloat(amountStr);if(!amount||amount<1){toast('Minimum stake is 1 SUI.','err');return}const amountMist=BigInt(Math.round(amount*1e9));const old=btn.innerHTML;btn.disabled=true;btn.innerHTML='<span class="spin"></span>';try{const tx=new Transaction();const [coin]=tx.splitCoins(tx.gas,[amountMist]);tx.moveCall({target:'0x3::sui_system::request_add_stake',arguments:[tx.object(SYS),coin,tx.pure.address(validator)]});const res=await wallet.features['sui:signAndExecuteTransaction'].signAndExecuteTransaction({transaction:tx,account,chain:'sui:'+network});toast('Staked '+amount+' SUI ✓ <a href="'+explorerTx(res.digest)+'" target="_blank">view tx</a>','ok');setTimeout(loadMyStakes,1500)}catch(e){toast('Stake failed: '+(e.message||e),'err')}btn.disabled=false;btn.innerHTML=old}async function unstake(stakedId,btn){const old=btn.innerHTML;btn.disabled=true;btn.innerHTML='<span class="spin"></span>';try{const tx=new Transaction();tx.moveCall({target:'0x3::sui_system::request_withdraw_stake',arguments:[tx.object(SYS),tx.object(stakedId)]});const res=await wallet.features['sui:signAndExecuteTransaction'].signAndExecuteTransaction({transaction:tx,account,chain:'sui:'+network});toast('Unstake requested ✓ <a href="'+explorerTx(res.digest)+'" target="_blank">view tx</a>','ok');setTimeout(loadMyStakes,1500)}catch(e){toast('Unstake failed: '+(e.message||e),'err')}btn.disabled=false;btn.innerHTML=old}async function loadMyStakes(){if(!account){$('mySection').style.display='none';return}try{const data=await client.getStakes({owner:account.address});const box=$('myStakes');if(!data.length){$('mySection').style.display='none';return}$('mySection').style.display='block';box.innerHTML='';const nameOf=a=>(validators.find(v=>v.address===a)?.name)||short(a);data.forEach(group=>{group.stakes.forEach(s=>{const principal=suiFromMist(s.principal);const reward=s.estimatedReward?suiFromMist(s.estimatedReward):0;const pending=s.status!=='Active';const row=document.createElement('div');row.style.cssText='display:flex;align-items:center;justify-content:space-between;gap:12px;background:var(--card);border:1px solid var(--line);border-radius:13px;padding:13px 16px;flex-wrap:wrap';row.innerHTML='<div><div style="font-family:var(--display);font-weight:700;font-size:16px">'+fmt(principal,4)+' SUI</div><div style="font-family:var(--mono);font-size:11px;color:var(--ink-soft)">'+nameOf(group.validatorAddress)+'</div></div><div style="text-align:right">'+(reward?'<div style="font-size:12.5px;color:var(--mint)">+'+fmt(reward,4)+' SUI rewards</div>':'')+(pending?'<span style="font-family:var(--mono);font-size:11px;color:var(--warn)">activating next epoch</span>':'')+'</div><button class="btn btn-ghost">Unstake</button>';const btn=row.querySelector('button');btn.onclick=()=>unstake(s.stakedSuiId,btn);box.appendChild(row)})})}catch(e){}}function setNetwork(net){network=net;client=new SuiClient({url:getFullnodeUrl(net)});document.querySelectorAll('#netToggle button').forEach(b=>b.classList.toggle('active',b.dataset.net===net));const notice=$('netNotice');if(net==='mainnet'){notice.className='notice';notice.innerHTML='<span>⚠</span><span><strong>Mainnet — real funds.</strong> Transactions stake real SUI. Always review the details in your wallet before approving. Minimum stake is 1 SUI.</span>'}else{notice.className='notice testnet';notice.innerHTML='<span>✓</span><span><strong>Testnet — safe to experiment.</strong> Uses test SUI with no real value. Get tokens from the Sui testnet faucet. Minimum stake is 1 SUI.</span>'}loadSystem();loadMyStakes()}$('connectBtn').onclick=openModal;$('search').oninput=renderValidators;$('sort').onchange=renderValidators;document.querySelectorAll('#netToggle button').forEach(b=>b.onclick=()=>setNetwork(b.dataset.net));getWallets().on('register',()=>{if($('modal').classList.contains('show'))openModal()});loadSystem();</script></body></html>