0x68575b07…67c7·#25,913,806·view on Etherscan
waitTx(h);
forgetUnlocked(u.id);
toast(`Withdrew ${u.amount} ${u.symbol}.`);
await loadUnlocked(); renderList();
} catch(e){ fail(e); }
}
async function refundTipIfAny(t){
if(!t.tipped) return '';
const gate=await getGate();
if(!gate) return '';
try {
txShow('Refunding the keeper tip','Confirm in your wallet');
await waitTx(await sendTx({from:S.account,to:gate,data:c1(SEL.refundTip,t.id)}));
return ' Tip refunded.';
} catch(e){
return isRejection(e) ? ' Tip left on the gate — refund it later with gate.refundTip.'
: ' Tip is still on the gate; refund it later with gate.refundTip.';
}
}
async function doForgetInbound(t){
if(!guardWritable()) return;
try {
await slowTx(c1(SEL.forgetInbound, t.id), 'Dismissing…', 'Confirm in your wallet');
forgetUnlocked(t.id);
toast('Dismissed from your list. The transfer itself is unchanged — its link still opens it.', 6000);
hideModal(el.detailModal);
loadTransfers(true);
} catch(e){ fail(e); }
}
async function doClaim(t){
if(nw()<t.unlockTime){ toast(`${fmtTime(t.unlockTime-nw())} remaining`); return; }
const guardian=S.hasGuardian, key=unlockedKey();
try {
if(guardian) rememberUnlocked(t, key);
await slowTx(c1(guardian?SEL.unlock:SEL.claim,t.id),
guardian?'Unlocking…':'Claiming…','Confirm in your wallet');
toast(guardian ? 'Unlocked. It is now in Unlocked, awaiting a guardian-approved withdrawal.' : 'Claimed.', 6000);
loadTransfers(true);
} catch(e){ fail(e); }
}
async function doReverse(t){
if(nw()>=t.unlockTime){ toast("The timelock expired — this can no longer be reversed"); return; }
const guarded=S.hasGuardian, key=unlockedKey();
try {
const data = guarded ? c1(SEL.reverse,t.id)
: cd(SEL.multicall,['bytes[]'],[[c1(SEL.reverse,t.id),wfCall(t)]]);
if(guarded) rememberUnlocked(t, key);
await slowTx(data,'Reversing the transfer…','Confirm in your wallet');
const tip=await refundTipIfAny(t);
toast((guarded?'Reversed. It is now in Unlocked, awaiting a guardian-approved withdrawal.':'Reversed and returned.')+tip,6000);
loadTransfers(true);
} catch(e){ fail(e); }
}
async function doClawback(t){
const ready=t.unlockTime+GRACE;
if(nw()<ready){ toast(`Recovery available in ${fmtTime(ready-nw())}`); return; }
const guarded=S.hasGuardian, key=unlockedKey();
try {
const data = guarded ? c1(SEL.clawback,t.id)
: cd(SEL.multicall,['bytes[]'],[[c1(SEL.clawback,t.id),wfCall(t)]]);
if(guarded) rememberUnlocked(t, key);
await slowTx(data,'Recovering…','Confirm in your wallet');
const tip=await refundTipIfAny(t);
toast((guarded?'Recovered. It is now in Unlocked, awaiting a guardian-approved withdrawal.':'Recovered.')+tip,6000);
loadTransfers(true);
} catch(e){ fail(e); }
}
const LOADER = '<svg viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" class="loader" role="img" aria-label="Loading"><g opacity="1"><animate attributeName="opacity" values="1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 155,160 200,135" fill="#FF6B9D" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,135 245,160" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="155,160 200,135 200,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,135 245,160 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="155,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 245,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="155" y1="160" x2="245" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 160,160 200,132" fill="#FF6B9D" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,132 240,160" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="160,160 200,132 200,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,132 240,160 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="160,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 240,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="160" y1="160" x2="240" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 170,160 200,130" fill="#FF6B9D" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,130 235,160" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="200,130 235,160 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="170,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 235,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="170" y1="160" x2="235" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;1;0;0;0;0;0;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 180,160 200,135" fill="#FF6B9D" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,135 220,160" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="200,135 220,160 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="180,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 220,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="180" y1="160" x2="220" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;1;0;0;0;0;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 195,160 200,140" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,140 205,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="195,160 200,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><polygon points="200,160 205,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="195" y1="160" x2="205" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 180,160 200,135" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,135 220,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="180,160 200,135 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="180,160 200,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><polygon points="200,160 220,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="180" y1="160" x2="220" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 165,160 200,130" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,130 230,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="165,160 200,130 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="165,160 200,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><polygon points="200,160 230,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="165" y1="160" x2="230" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;1;0;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 160,160 200,132" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,132 240,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="160,160 200,132 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,132 240,160 200,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="160,160 200,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><polygon points="200,160 240,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="160" y1="160" x2="240" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;0;1;0;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 155,160 200,135" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,135 245,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="155,160 200,135 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,135 245,160 200,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="155,160 200,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><polygon points="200,160 245,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="155" y1="160" x2="245" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;0;0;1;0;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 160,160 200,132" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,132 240,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="160,160 200,132 200,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,132 240,160 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="160,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 240,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="160" y1="160" x2="240" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;0;0;0;1;0;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 170,160 200,130" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,130 235,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,130 235,160 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="170,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 235,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="170" y1="160" x2="235" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;0;0;0;0;1;0;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 180,160 200,135" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,135 220,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,135 220,160 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="180,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 220,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="180" y1="160" x2="220" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;0;0;0;0;0;1;0;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 195,160 200,140" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,140 205,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="195,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 205,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="195" y1="160" x2="205" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;0;0;0;0;0;0;1;0;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 180,160 200,135" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,135 220,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,135 220,160 200,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="180,160 200,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><polygon points="200,160 220,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="180" y1="160" x2="220" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;0;0;0;0;0;0;0;1;0" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 170,160 200,130" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,130 235,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,130 235,160 200,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="170,160 200,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><polygon points="200,160 235,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="170" y1="160" x2="235" y2="160" stroke="#000000" stroke-width="2"/></g><g opacity="0"><animate attributeName="opacity" values="0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;1" dur="3.2s" repeatCount="indefinite"/><polygon points="200,80 160,160 200,132" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,132 240,160" fill="#FF6B9D" stroke="#000000" stroke-width="2"/><polygon points="160,160 200,132 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="200,132 240,160 200,160" fill="#FF6B9D" stroke="#000000" stroke-width="2"/><polygon points="160,160 200,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><polygon points="200,160 240,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="160" y1="160" x2="240" y2="160" stroke="#000000" stroke-width="2"/></g></svg>';
const LOADER_STILL = '<svg viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" class="loader" role="img" aria-label="Loading"><g opacity="1"><polygon points="200,80 155,160 200,135" fill="#FF6B9D" stroke="#000000" stroke-width="2"/><polygon points="200,80 200,135 245,160" fill="#00D4FF" stroke="#000000" stroke-width="2"/><polygon points="155,160 200,135 200,160" fill="#FFE066" stroke="#000000" stroke-width="2"/><polygon points="200,135 245,160 200,160" fill="#66D9A6" stroke="#000000" stroke-width="2"/><polygon points="155,160 200,160 200,240" fill="#FF9F40" stroke="#000000" stroke-width="2"/><polygon points="200,160 245,160 200,240" fill="#B967DB" stroke="#000000" stroke-width="2"/><line x1="200" y1="80" x2="200" y2="240" stroke="#000000" stroke-width="2"/><line x1="155" y1="160" x2="245" y2="160" stroke="#000000" stroke-width="2"/></g></svg>';
function loaderNode(){
const d=document.createElement('div');
d.className='loading-wrap';
d.innerHTML = matchMedia('(prefers-reduced-motion: reduce)').matches ? LOADER_STILL : LOADER;
return d;
}
const ICONS = {
1:'<svg viewBox="0 0 32 32" aria-hidden="true">'
+'<rect width="32" height="32" fill="#627EEA"/>'
+'<g transform="translate(4 4)" fill="#fff">'
+'<path d="M11.944 17.97 4.58 13.62 11.943 24l7.37-10.38-7.372 4.35h.003zM12.056 0 4.69 12.223l7.365 4.354 7.365-4.35L12.056 0z"/>'
+'</g></svg>',
4663:'<svg viewBox="0 0 32 32" aria-hidden="true">'
+'<rect width="32" height="32" fill="#CCFF00"/>'
+'<g transform="translate(4 4)" fill="#110E08">'
+'<path d="M2.84 24h.53c.096 0 .192-.048.224-.128C7.591 13.696 11.94 8.656 14.67 5.638c.112-.128.064-.225-.096-.225h-4.88a.55.55 0 0 0-.45.225L5.746 9.972c-.514.642-.642 1.236-.642 2.086v4.43c-1.14 3.194-1.862 5.361-2.392 7.32-.032.125.016.192.129.192M20.447.646c-.754-.802-4.157-.834-5.73-.224a3 3 0 0 0-.786.465 41 41 0 0 0-3.323 3.178c-.112.113-.064.225.097.225h5.409c.497 0 .786.289.786.786v6.1c0 .16.128.208.225.064l3.258-4.254c.53-.69.69-.898.835-1.861.192-1.413.08-3.58-.77-4.479m-6.982 16.18 2.231-3.676a.7.7 0 0 0 .064-.29V6.73c0-.16-.112-.225-.224-.097-3.355 3.74-5.971 7.672-8.395 12.407-.06.12.016.225.16.177l5.009-1.54c.565-.174.882-.402 1.155-.852"/>'
+'</g></svg>',
8453:'<svg viewBox="0 0 32 32" aria-hidden="true">'
+'<rect width="32" height="32" fill="#0052FF"/>'
+'<path d="M16 5.4A10.6 10.6 0 0 0 5.5 14.7h13.9v2.6H5.5A10.6 10.6 0 1 0 16 5.4Z"'
+' fill="#fff" transform="rotate(180 16 16)"/>'
+'</svg>',
};
function destinations(){
if(S.chain!==MAINNET || S.token!==ZERO) return [];
return CHAIN_IDS.filter(id => id!==MAINNET && BRIDGES[id] && BRIDGES[id].from===MAINNET);
}
function buildDestRow(){
const opts = destinations();
el.fDest.hidden = !opts.length;
if(!opts.length){ S.dest=null; return; }
const row=el.destRow;
row.replaceChildren();
const mk=(id,label,live)=>{
const b=document.createElement('button');
b.type='button'; b.className='opt'; b.dataset.dest=String(id);
b.textContent=label;
b.disabled=!live;
b.title = live ? ''
: S.slowDeployed[id]!==true ? `SLOW is not deployed on ${cfg(id).name} yet`
: (S.account && S.accountIsContract===null)
? `Still checking whether this account can be reversed from on ${cfg(id).name}`
: `A transfer bridged to ${cfg(id).name} from this account could not be reversed or recovered`;
b.setAttribute('aria-pressed', String((S.dest||MAINNET)===id));
row.appendChild(b);
};
mk(MAINNET, 'Ethereum', true);
for(const id of opts) mk(id, cfg(id).short, canBridge(S.chain, id));
const live = opts.filter(id=>canBridge(S.chain, id)).length;
const checking = !!S.account && S.accountIsContract===null;
if(S.dest && !canBridge(S.chain, S.dest)) S.dest=null;
el.destHint.textContent = live ? '' : checking ? 'checking…' : 'awaiting deployment';
}
function buildTokenGrid(){
const g=el.cryptoGrid, c=cfg();
el.assetHint.textContent=c.name;
g.replaceChildren();
for(const t of cfg().tokens){
const b=document.createElement('button');
b.type='button'; b.className='crypto';
b.dataset.symbol=t.symbol; b.dataset.token=t.address.toLowerCase();
b.dataset.decimals=String(t.decimals);
b.textContent=t.symbol;
b.style.borderLeftColor=railOf(t.symbol,t.address);
b.setAttribute('aria-pressed','false');
g.appendChild(b);
}
}
function presetsFor(sym){ return PRESETS[sym]||PRESETS.default; }
function paintPresets(){
const p=presetsFor(S.symbol);
const btns=[...el.amountRow.querySelectorAll('[data-amount]')];
btns.forEach((b,i)=>{ b.dataset.amount=p[i]; b.textContent=p[i]; });
if(S.balance!==null && S.token && S.symbol){
el.balHint.textContent=`${fmtAmt(S.balance,S.decimals)} ${S.symbol}`;
for(const b of btns){
let over=false;
try { over = parseUnits(b.dataset.amount,S.decimals) > S.balance; } catch(e){}
b.disabled=over;
b.title=over?`More than your ${S.symbol} balance`:'';
}
} else {
el.balHint.textContent = !S.token ? 'pick an asset first'
: !S.account ? 'connect to see balance' : '';
for(const b of btns){ b.disabled=false; b.title=''; }
}
el.maxBtn.disabled = S.balance===null;
render(); renderReview();
}
function paintChain(){
const c=cfg();
el.chainIcon.innerHTML=ICONS[c.id]||'';
el.chainName.textContent=c.name;
el.chainBtn.title=`${c.name} · chain ${c.id}`;
el.chainBtn.setAttribute('aria-label',`Network: ${c.name}. Change.`);
}
function paintNet(){
el.netDot.hidden = S.readOk;
el.netDot.title = S.readOk ? '' : `No RPC reachable for ${cfg().name}`;
}
function paintWallet(){
const on=!!S.account;
el.walletBtn.querySelector('.lbl').textContent = on ? (S.ensName||shortAddr(S.account)) : 'Connect';
el.walletBtn.classList.toggle('on',on);
el.walletBtn.title = on ? `${S.account}${S.walletName?' · '+S.walletName:''} — disconnect` : 'Connect a wallet';
}
function paintDeployed(){
const live=S.slowDeployed[S.chain];
if(live===undefined && S.slowUnknown===S.chain){
el.chainWarn.hidden=false;
el.chainWarn.textContent=`Could not reach ${cfg().name} to check SLOW is there. Reads may be incomplete.`;
render(); return;
}
el.chainWarn.hidden = live!==false;
if(live===false) el.chainWarn.textContent = S.slowMismatch===S.chain
? `The contract at this address on ${cfg().name} is not the build this page speaks to.`
: `SLOW is not deployed on ${cfg().name} yet.`;
render();
}
function render(){
const b=document.body;
b.classList.toggle('v-home',S.view==='home');
b.classList.toggle('v-send',S.view==='send');
b.classList.toggle('v-take',S.view==='take');
b.classList.toggle('v-guard',S.view==='guard');
el.segSend.setAttribute('aria-selected',String(S.view==='send'));
el.segTake.setAttribute('aria-selected',String(S.view==='take'));
el.segGuard.setAttribute('aria-selected',String(S.view==='guard'));
el.fAmount.classList.toggle('locked',S.step<1); el.fAmount.inert = S.step<1;
el.fTime.classList.toggle('locked',S.step<2); el.fTime.inert = S.step<2;
const isCustom = S.token && !qs(`.crypto[data-token="${S.token}" i]`);
el.customTokenOpt.setAttribute('aria-pressed',String(!!isCustom));
el.customTokenOpt.textContent = isCustom?S.symbol:'+ Custom token';
el.customTokenOpt.style.borderLeft = isCustom?`5px solid ${tokenColor(S.token)}`:'';
el.cryptoGrid.classList.toggle('dim',!!isCustom);
qsa('.crypto').forEach(c=>c.setAttribute('aria-pressed',String(c.dataset.token.toLowerCase()===S.token)));
el.amountRow.querySelectorAll('.opt').forEach(o=>
o.setAttribute('aria-pressed',String(o.dataset.amount===S.amount)));
const customDly = S.delay && !qs(`#timeRow [data-time="${S.delay}"]`);
el.timeRow.querySelectorAll('.opt').forEach(o=>{
const on = o===el.customTimeOpt ? !!customDly : parseInt(o.dataset.time)===S.delay;
o.setAttribute('aria-pressed',String(!!on));
});
el.customTimeOpt.textContent = customDly?S.delayDisplay:'Custom';
paintFoot();
el.timeHint.textContent = S.step<2 ? 'enter an amount first' : '';
el.tabOut.setAttribute('aria-selected',String(S.tab==='outbound'));
el.tabIn.setAttribute('aria-selected',String(S.tab==='inbound'));
}
function resetForm(){
S.token=S.symbol=null; S.decimals=18; S.amount=S.delay=S.delayDisplay=null;
S.resolved=S.resolvedName=null; S.resolving=false; S.step=0; S.autoClaim=false; S.tip=0n; S.balance=null;
el.recipientInput.value=''; setNote(el.ens,'');
el.amountInput.value=''; setNote(el.amountNote,''); el.planNote.textContent='';
el.dInput.value=el.hInput.value=el.mInput.value=el.sInput.value='';
el.autoClaimChk.checked=false; el.tipPre.textContent=''; el.balHint.textContent='';
el.fReview.hidden=true;
paintPresets();
}
function setView(v){
if(v==='send') paintPreview();
S.view=v;
if(v==='home') resetForm();
if(v!=='take'){ stopTimer(); }
if(v!=='send') hideAllModals();
render();
if(v==='take'){ renderList(); loadTransfers(true); }
if(v==='guard'){ renderGuard(); loadGuard(); }
}
const isSender = t => !!S.account && !!t.from && t.from.toLowerCase()===S.account.toLowerCase();
function statusOf(t){
const n=nw();
const expired = n>=t.unlockTime;
const inbound = S.tab==='inbound';
if(inbound) return expired
? {key:'ready', text:'Ready to claim', act:'Claim'}
: {key:'pending', text:`Unlocks in ${fmtTime(t.unlockTime-n)}`, act:null};
if(!isSender(t)){
const via = S.account && t.from && t.from.toLowerCase()===aliasOf(S.account).toLowerCase();
return expired
? {key:'settling', text: via ? 'Bridged in — awaiting the recipient' : 'Awaiting the recipient', act:null}
: {key:'pending', text:`Unlocks in ${fmtTime(t.unlockTime-n)}`+(via?' · bridged in':''), act:null};
}
if(!expired) return {key:'pending', text:`Unlocks in ${fmtTime(t.unlockTime-n)}`, act:'Reverse'};
if(n>=t.unlockTime+GRACE) return {key:'recover', text:'Unclaimed — recoverable', act:'Recover'};
return {key:'settling', text: