Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions src/app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,29 @@ export default function AboutPage() {
13 live benchmarks. ~150 (provider × chain) probe pairs. Every metric is queryable on the public Prometheus and reproducible from the harness source.
</p>

<SectionRule label="How it works" number="iii" />
<SectionRule label="Independence and disclosure" number="iii" />
<p className="text-base leading-relaxed text-ink-soft">
OpenChainBench is funded by <a className="lnk" href="https://mobula.io" rel="noopener">Mobula</a> because we needed honest infrastructure benchmark data internally and saw no neutral source existed. The site is open-sourced because the industry needs it.
</p>
<p className="mt-4 text-base leading-relaxed text-ink-soft">
<strong>Mobula competes in five live benchmarks</strong>: aggregator head lag, bridge fee, bridge quote latency, network coverage and metadata coverage. Mobula currently leads aggregator head lag and bridge quote latency. This is a real conflict of interest and we want it visible above the fold, not buried.
</p>
<p className="mt-4 text-base leading-relaxed text-ink-soft">
Three safeguards stand against the conflict:
</p>
<ul className="mt-3 space-y-3 text-base leading-relaxed text-ink-soft">
<li className="flex gap-3"><span className="text-ink-faint">·</span><span><strong>Open Prometheus data</strong>. Every number on the site is a literal <code>quantile_over_time</code> query. Anyone can hit our <Link className="lnk" href="/api/citable">/api/citable</Link> or <code>/api/stat/&lt;slug&gt;</code> endpoint and re-derive the leaderboard with their own aggregation. If Mobula were inflating its rank, the raw data would show it.</span></li>
<li className="flex gap-3"><span className="text-ink-faint">·</span><span><strong>Open harness source</strong>. Every harness is on <a className="lnk" href="https://github.com/ChainBench/OpenChainBench/tree/main/harnesses" rel="noopener">GitHub under harnesses/</a>. Clone, run <code>docker compose up</code>, your <code>/metrics</code> endpoint emits the same numbers ours does within 30 seconds.</span></li>
<li className="flex gap-3"><span className="text-ink-faint">·</span><span><strong>Public methodology review</strong>. We invite external review and ship the fixes publicly. In June 2026 the Coinpaprika data team flagged four issues on the stablecoin peg and oracle deviation benches. We shipped three of them in pull requests <a className="lnk" href="https://github.com/ChainBench/OpenChainBench/pull/349" rel="noopener">#349</a>, <a className="lnk" href="https://github.com/ChainBench/OpenChainBench/pull/352" rel="noopener">#352</a> and <a className="lnk" href="https://github.com/ChainBench/OpenChainBench/pull/353" rel="noopener">#353</a> within twenty-four hours and pushed back on the fourth with citations to CME, Chainlink and CoinGecko convention.</span></li>
</ul>
<p className="mt-4 text-base leading-relaxed text-ink-soft">
We do not run a paid tier. We do not sell ranking slots. We do not take provider sponsorship in exchange for inclusion. There is no token. If you spot any deviation from this policy, file a <a className="lnk" href="https://github.com/ChainBench/OpenChainBench/security/advisories/new" rel="noopener">private security advisory</a> and we will treat it as the integrity incident it would be.
</p>
<p className="mt-4 text-base leading-relaxed text-ink-soft">
Hosting and infrastructure costs are paid by Mobula. The site runs on Vercel; harnesses run on Railway. We are open to grant funding that preserves editorial independence, but we will not accept funding from any party we benchmark.
</p>

<SectionRule label="How it works" number="iv" />
<p className="text-base leading-relaxed text-ink-soft">
Every benchmark is a YAML spec plus a harness. The spec describes what to measure, which providers, which Prometheus queries hold the numbers; the harness runs continuously on Railway and exposes those metrics. A single shared Prometheus scrapes every harness; the site queries Prometheus directly and re-renders every minute. Every provider is rendered with equal visual weight. readers do their own ranking.
</p>
Expand All @@ -62,15 +84,15 @@ export default function AboutPage() {
walks through the steps. New providers, new metrics, new chains. all welcome via pull request.
</p>

<SectionRule label="What you can do" number="iv" />
<SectionRule label="What you can do" number="v" />
<ul className="space-y-4 text-base leading-relaxed text-ink-soft">
<li className="flex gap-3"><span className="text-ink-faint">·</span><span><strong>Read</strong> the{" "}<Link className="lnk" href="/#latest">live benchmarks</Link>{" "}.</span></li>
<li className="flex gap-3"><span className="text-ink-faint">·</span><span><strong>Reproduce</strong> any number. the{" "}<Link className="lnk" href="/methodology">methodology</Link>{" "}page tells you how.</span></li>
<li className="flex gap-3"><span className="text-ink-faint">·</span><span><strong>Contribute</strong> a harness via{" "}<a className="lnk" href="https://github.com/ChainBench/OpenChainBench">GitHub</a>. Pull requests for new providers and new benchmarks are reviewed openly.</span></li>
<li className="flex gap-3"><span className="text-ink-faint">·</span><span><strong>Discuss</strong> ideas in{" "}<a className="lnk" href="https://github.com/ChainBench/OpenChainBench/discussions">GitHub Discussions</a>{" "}or follow{" "}<a className="lnk" href="https://x.com/OpenChainBench">@OpenChainBench</a>.</span></li>
</ul>

<SectionRule label="Contact" number="v" />
<SectionRule label="Contact" number="vi" />
<p className="text-base leading-relaxed text-ink-soft">
See a number you can&apos;t reproduce? File a{" "}
<a className="lnk" href="https://github.com/ChainBench/OpenChainBench/issues/new/choose">
Expand Down
109 changes: 102 additions & 7 deletions src/app/products/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -403,33 +403,120 @@ export default async function ProviderPage({
stays accurate without redeploying.
</p>
<ul className="mt-4 grid gap-3 sm:grid-cols-2">
{sorted.filter((a) => a.rank === 1).map((a) => {
{(() => {
// Generate the list of badge cards to render. For benches WITHOUT
// chain dimensions, the global aggregate badge is honest and we
// emit one card per #1 finish. For benches WITH chain dimensions
// we walk rankPerChain instead:
// - If the provider leads on EVERY declared chain (and the
// aggregate #1 confirms it), we keep a single global badge.
// A true cross-chain leader gets the unscoped claim.
// - Otherwise we emit one badge PER chain the provider leads
// and SKIP the global aggregate badge entirely. Without this
// guard a provider that wins one chain out of ten still
// shows a misleading "#1 on Fastest free public RPC" badge
// even though they trail elsewhere. Embedders broadcasting
// that badge would be parroting an inaccurate claim, which
// is the exact reputation hit we built the bench to avoid.
type BadgeCard = {
key: string;
title: string;
chain?: { value: string; label: string };
benchSlug: string;
};
const cards: BadgeCard[] = [];
for (const a of sorted) {
const chainDims = a.benchmark.chainDimensions ?? [];
const realChains = chainDims.filter((c) => c.value !== "all");
const perChain = a.rankPerChain ?? {};
const wonChains = realChains.filter(
(c) => perChain[c.value]?.rank === 1,
);
const hasChainDims = realChains.length > 0;
const isGlobalNumberOne = a.rank === 1;
if (!hasChainDims) {
if (isGlobalNumberOne) {
cards.push({
key: a.benchmark.slug,
title: a.benchmark.title,
benchSlug: a.benchmark.slug,
});
}
continue;
}
const leadsAllChains =
realChains.length > 0 &&
wonChains.length === realChains.length;
if (isGlobalNumberOne && leadsAllChains) {
cards.push({
key: a.benchmark.slug,
title: a.benchmark.title,
benchSlug: a.benchmark.slug,
});
continue;
}
for (const c of wonChains) {
cards.push({
key: `${a.benchmark.slug}-${c.value}`,
title: a.benchmark.title,
chain: c,
benchSlug: a.benchmark.slug,
});
}
}
return cards;
})().map((card) => {
// Absolute URL is the one shipped to embedders (it has to
// work from any third-party origin), but the in-page preview
// <img> uses a relative path so it loads under the current
// origin's CSP (`img-src 'self'`). Without this, the preview
// shows the browser's broken-image glyph on every non-prod
// origin (staging Preview URLs, Vercel branch previews, etc.)
// because the CSP refuses the cross-origin fetch.
const badgePath = `/api/badge/${a.benchmark.slug}/${p.slug}`;
const qs = card.chain ? `?chain=${encodeURIComponent(card.chain.value)}` : "";
const badgePath = `/api/badge/${card.benchSlug}/${p.slug}${qs}`;
const badgeUrl = `${SITE.url}${badgePath}`;
const targetUrl = `${SITE.url}/benchmarks/${a.benchmark.slug}`;
const html = `<a href="${targetUrl}"><img src="${badgeUrl}" alt="Ranked #1 on OpenChainBench: ${a.benchmark.title}" height="36" /></a>`;
const targetUrl = `${SITE.url}/benchmarks/${card.benchSlug}${qs}`;
const scopeSuffix = card.chain ? ` on ${card.chain.label}` : "";
const cardTitle = card.chain
? `${card.title} — ${card.chain.label}`
: card.title;
const altText = `Ranked #1 on OpenChainBench: ${card.title}${scopeSuffix}`;
const html = `<a href="${targetUrl}"><img src="${badgeUrl}" alt="${altText}" height="36" /></a>`;
const markdown = `[![${altText}](${badgeUrl})](${targetUrl})`;
// Pre-baked X intent. Providers click → tweet draft opens
// with the ranking claim, the bench URL and the OCB handle
// already filled in. Removes the friction of writing the
// post themselves and gives us the canonical anchor text
// back as a tagged tweet on every share.
const tweetText = `Independently benchmarked #1 on ${card.title}${scopeSuffix} by @OpenChainBench.\n\nReproducible methodology, live data:`;
const tweetIntent = `https://x.com/intent/tweet?text=${encodeURIComponent(tweetText)}&url=${encodeURIComponent(targetUrl)}`;
return (
<li key={`badge-${a.benchmark.slug}`} className="card-soft p-4">
<li key={`badge-${card.key}`} className="card-soft p-4">
<p className="text-xs font-sans font-medium uppercase tracking-[0.18em] text-ink-muted">
{a.benchmark.title}
{cardTitle}
</p>
<div className="mt-3 flex items-center">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={badgePath}
alt={`Ranked #1 on OpenChainBench: ${a.benchmark.title}`}
alt={altText}
height={36}
loading="lazy"
decoding="async"
/>
</div>
<div className="mt-3 flex flex-wrap items-center gap-3 text-[11px] font-sans font-medium uppercase tracking-[0.18em] text-ink-muted">
<a
href={tweetIntent}
target="_blank"
rel="noopener"
className="inline-flex items-center gap-1 hover:text-ink"
>
Share on X
<ArrowUpRight size={11} strokeWidth={2} />
</a>
</div>
<details className="mt-3">
<summary className="cursor-pointer text-[11px] font-sans font-medium uppercase tracking-[0.18em] text-ink-muted hover:text-ink">
Copy HTML
Expand All @@ -438,6 +525,14 @@ export default async function ProviderPage({
{html}
</pre>
</details>
<details className="mt-2">
<summary className="cursor-pointer text-[11px] font-sans font-medium uppercase tracking-[0.18em] text-ink-muted hover:text-ink">
Copy Markdown
</summary>
<pre className="mt-2 overflow-x-auto rounded border border-rule bg-paper-soft p-2 text-[11px] leading-snug">
{markdown}
</pre>
</details>
</li>
);
})}
Expand Down
Loading