charter-attestation-verifier / tree / app.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
import { verifyCharter, httpRpc, httpIpfs, NETWORKS, CHARTER_SCHEMA } from './verifier.js';

const $ = (id) => document.getElementById(id);
const out = $('result');
$('schema').textContent = CHARTER_SCHEMA;

const esc = (s) => String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]);

function render(r, network, label) {
  const when = r.attestation.time ? new Date(r.attestation.time * 1000).toISOString().replace('.000Z', ' UTC').replace('T', ' ') : 'unknown';
  const link = label ? '' : ` <a href="${NETWORKS[network].explorer}${esc(r.attestation.uid)}" target="_blank" rel="noopener">open on easscan</a>`;
  const rows = r.texts.map((t) => `<tr>
      <td>${esc(t.name)}<br><code>${esc(t.cid)}</code></td>
      <td class="${t.match ? 'match' : 'mismatch'}">${t.match ? 'match' : t.error ? 'not fetched' : 'mismatch'}</td>
      <td><code>expected ${esc(t.expected)}</code><br><code>actual ${esc(t.actual ?? 'none')}</code>${t.error ? `<br>${esc(t.error)}` : ''}</td>
    </tr>`).join('');
  out.innerHTML = `<div class="card">
    <p class="status ${r.ok ? 'ok' : 'error'}">${r.ok ? 'Verified: every text matches the attestation.' : `Not verified: ${esc(r.reason)}.`}</p>
    ${label ? `<p class="muted">${esc(label)}</p>` : ''}
    <dl>
      <dt>UID</dt><dd>${esc(r.attestation.uid)}${link}</dd>
      <dt>Network</dt><dd>${esc(network)}</dd>
      <dt>Attester</dt><dd>${esc(r.attestation.attester ?? 'unknown')}</dd>
      <dt>Time</dt><dd>${esc(when)}</dd>
      <dt>Revoked</dt><dd>${r.attestation.revoked ? 'yes' : 'no'}</dd>
      ${r.charter ? `<dt>Version</dt><dd>${esc(r.charter.version)} (${esc(r.charter.date)})</dd>` : ''}
    </dl>
    ${rows ? `<table><thead><tr><th>Text</th><th>Result</th><th>Digests</th></tr></thead><tbody>${rows}</tbody></table>` : ''}
  </div>`;
}

async function run(uid, network) {
  out.innerHTML = '<p class="muted">Checking...</p>';
  const rpcUrl = $('rpcUrl').value.trim() || NETWORKS[network].rpcUrl;
  const gateway = $('gateway').value.trim() || undefined;
  const r = await verifyCharter({ uid, network, rpc: httpRpc(rpcUrl), ipfs: httpIpfs(gateway) });
  render(r, network);
  const u = new URL(location.href);
  u.searchParams.set('network', network);
  u.searchParams.set('uid', uid);
  history.replaceState(null, '', u);
}

async function demo(tampered) {
  const fx = await (await fetch('test/fixtures.json')).json();
  const byCid = Object.fromEntries(fx.names.map((n, i) => [fx.cids[i], fx.texts[n]]));
  if (tampered) byCid[fx.cids[1]] = fx.texts.constitution.replace('Article 1', 'Article 2');
  const r = await verifyCharter({
    uid: fx.uid,
    network: 'base-sepolia',
    rpc: async () => fx.attestation,
    ipfs: async (cid) => new TextEncoder().encode(byCid[cid]),
  });
  render(r, 'base-sepolia', tampered
    ? 'Demo with fixture data: the constitution text was changed by one character, so only its digest differs.'
    : 'Demo with fixture data: a sample attestation and its three sample texts, no network.');
}

$('lookup').addEventListener('submit', (e) => {
  e.preventDefault();
  run($('uid').value.trim(), $('network').value);
});
$('demo').addEventListener('click', () => demo(false));
$('demoTampered').addEventListener('click', () => demo(true));

const q = new URLSearchParams(location.search);
if (q.get('network') in NETWORKS) $('network').value = q.get('network');
if (q.get('uid')) {
  $('uid').value = q.get('uid');
  run(q.get('uid'), $('network').value);
} else if (q.get('demo')) {
  demo(q.get('demo') === 'tampered');
}

agentgate-source: code mirror on Cloudflare Pages. All repos