The Trust Grade
Every ChainRender app carries a trust grade — a single letter (A / B / C) that tells a user, before they interact, exactly how trustless the app is. It is computed on-chain, and the SDK computes an identical grade locally (they are drift-locked), so you can see your app's grade as you build it.
What the grades mean
| Grade | Word | Meaning |
|---|---|---|
| A | Trustless | Fully on-chain, no external dependencies. Everything you see is computed from chain state. |
| B | Pinned | Depends on an immutable, content-pinned external asset (e.g. an IPFS hash). Verifiable, but off-chain. |
| C | Live | Depends on something that can change — a live off-chain fetch, a mutable pointer, or an unproven asset. |
The grade is the worst link: one Grade-C part sets the headline, because a chain is only as trustless as its weakest dependency. But the grade is never just a letter — it comes with an itemized breakdown naming every deviation, so the user (and you) can see exactly why a grade was assigned.
Why a grade instead of a checkmark
A binary "safe / unsafe" badge would be dishonest — trust is a spectrum, not a boolean. An app that renders a chart from live on-chain data (Grade A) and an app that embeds an image from a random web server (Grade C) are both "functional," but they are not equally trustworthy, and pretending otherwise would violate ChainRender's core discipline: marketing must never exceed what the code enforces.
The grade makes the trust cost legible. A user who wants maximum assurance uses only Grade-A apps. A user who accepts a pinned dependency uses Grade-B. Nobody is surprised, because the grade — and its reasons — are visible up front.
How it's computed (the reasoning)
The grade derives from the app's capability envelope — the union of everything the app can do and everything it depends on. The enforcer walks the composition and, for each part, classifies its dependencies along several axes (is data on-chain or fetched? is an asset immutable, attested, or mutable? does an action stay within the declared envelope?). Each axis has an honest floor:
- On-chain computation → contributes nothing negative (Grade A).
- A fail-closed enhancement (e.g. a GPU effect that degrades to an on-chain poster, or a fetch that falls back to complete on-chain data) → stays Grade A, because the trustless floor is intact even if the enhancement fails.
- A pinned/attested dependency (a raw-CIDv1 IPFS asset, pointer anchored on-chain, client-verified,
fail-closed) → Grade B. See the guide Grade B — a Pinned-IPFS Dependency
for how to declare it (
grade(app, { pinnedDep })). - A live fetch or mutable pointer that the output actually depends on → Grade C.
Crucially, the enforcer is conservative and fails closed: anything it cannot analyze is treated as unsafe (refused or downgraded), never optimistically passed. An unknown vocabulary token is refused, not rendered.
The relationship to safety-by-construction
The grade describes trust; the enforcer enforces safety. They're related but distinct:
- Some things are refused outright — an arbitrary-code escape hatch, an action that moves value while the app
never declared it can, a
{to, selector}not in the declared call set. These don't get a bad grade; they're rejected at registration. See The Capability Enforcer. - Everything that passes gets an honest grade reflecting its real dependencies.
So a registered ChainRender app is always safe (it can't smuggle a hidden transaction), and its grade tells you how trustless it is on top of that baseline safety.
Using the grade as a developer
import { grade } from "@chainrender/client";
const g = grade(myApp);
console.log(g.letter); // "A"
console.log(g.word); // "Trustless"
console.log(g.breakdown); // itemized deviations, if any
Watch the grade as you build. If adding a feature drops you from A to C, the breakdown tells you exactly which dependency did it — and you can decide whether that trade-off is worth it, before your users ever see it.
Resolvers and the grade (an important distinction)
Not all resolvers are equal for the grade:
- A client-side resolver — a JS function that fetches with viem/ethers in the browser (e.g.
getBalance,getBlock) — is an off-chain fetch. It grades C (Live). Routing data through a resolver function does not make it on-chain. - An on-chain resolver contract — a resolver address referenced by a Slot — reads and renders the value
on-chain during the
eth_call. It grades A (Trustless).
So a Slot bound to an on-chain resolver contract is Grade A; a Slot filled by a client-side JS resolver is Grade C. The grade tells the truth either way — an app using client-side resolvers is not "fully on-chain," and the grade correctly reflects that.
Related
- The Capability Enforcer — what gets refused vs. graded.
- Content Addressing — the immutability the grade builds on.
- Resolvers & Data Binding — how live data affects the grade.