Files
linkspin/public/assets/tx.js
T

43 lines
1.9 KiB
JavaScript

// Transaction viewer: renders one tx from /api/tx/<hash> (the server-side RPC
// relay, so the browser never talks to the chain directly and CSP stays 'self').
// This is the "verify it yourself" page for chains without a public explorer;
// when the config carries an explorer URL, feed links point there instead.
(async function () {
await IAP.renderNav('ledger');
const c = await IAP.getConfig();
const hash = location.pathname.split('/').pop();
IAP.$('txHash').textContent = hash;
IAP.$('txChain').textContent = 'on ' + (c.chainName || 'the settlement chain');
let r = null;
try { r = await (await fetch('/api/tx/' + hash)).json(); } catch (e) {}
const stat = IAP.$('txStatus');
if (!r || !r.found) {
stat.textContent = 'not found';
stat.className = 'badge amber';
IAP.$('txHint').hidden = false;
return;
}
const ok = r.status === '0x1';
stat.textContent = ok ? '✓ confirmed' : '✗ reverted';
stat.className = 'badge' + (ok ? '' : ' amber');
const hx = v => { try { return parseInt(v, 16); } catch (e) { return 0; } };
const rows = [
['Block', '#' + hx(r.blockNumber).toLocaleString()],
['Time', r.ts ? new Date(hx(r.ts) * 1000).toLocaleString() : 'pending'],
['From', r.from || ''],
['To (contract)', r.to || ''],
['Value sent', IAP.fmtPol(r.valueWei || '0') + ' POL'],
['Gas used', hx(r.gasUsed).toLocaleString()]
];
const tb = IAP.$('txTable');
tb.hidden = false;
tb.querySelector('tbody').innerHTML = rows.map(x =>
'<tr><td class="muted small" style="white-space:nowrap">' + x[0] + '</td>'
+ '<td class="mono small" style="overflow-wrap:anywhere">' + String(x[1]).replace(/[&<>]/g, '') + '</td></tr>').join('');
if (r.events && r.events.length) {
IAP.$('evCard').hidden = false;
const feed = IAP.$('evFeed');
for (const ev of r.events) feed.appendChild(IAP.feedRow(ev, c));
}
})();