Integrate the badge in a launchpad
Show every listed token's seal automatically, gate features on it, and verify signatures at build time.
A launchpad lists tokens by address. Every one of them has bytecode, and bytecode has a hash, so every one of them either has a seal or does not. Showing that is one lookup per token.
1. Resolve seals for a list
import { createPublicClient, http, keccak256, type Address } from "viem";
const client = createPublicClient({ transport: http("https://rpc.mainnet.chain.robinhood.com") });
const WORKER = "https://<worker>";
export async function sealsFor(addresses: Address[]) {
const all: Seal[] = await fetch(`${WORKER}/seals`, { next: { revalidate: 60 } }).then((r) => r.json());
const byHash = new Map(all.map((s) => [s.hash, s]));
const codes = await Promise.all(addresses.map((a) => client.getCode({ address: a })));
return addresses.map((a, i) => ({ address: a, seal: codes[i] && codes[i] !== "0x" ? byHash.get(keccak256(codes[i]!)) ?? null : null }));
}
One request for all seals, one eth_getCode per token (batch it through multicall or your indexer if you have one).
2. Show it on the card
8/8 · signed, linked to https://zkcheck.dev/seals/<hash>. Nothing else. Displaying the badge has the component and the list of things not to write.
3. Gate on it, carefully
You can require a seal to list, or to be featured. If you do:
- gate on the count, and say which count (
passed === 8, or>= 7); - gate on
proven === "zkvm"only once such seals exist, and say so; - never gate on the review's content, which is an opinion.
A launchpad that lists only 8 of 8 tokens is telling its users something precise: every token here has no mint, no drain, a capped tax, no blacklist, no pause, no proxy, a clear sell path and no self-destruct, as of its sealed bytecode. It is not telling them the token is good, and the gate's copy should say that.
4. Verify at build
If your page displays a badge, verify the signature once and cache the result. Verify a seal yourself. Refuse to display any seal whose signature does not recover to the auditor address you have pinned, and refresh the pinned address from GET / on the worker on a schedule so an auditor key rotation does not break you.
5. Let developers seal from your page
A Get a zk review link to https://zkcheck.dev/seal next to your launch form is enough. The developer connects their own GitHub; you never touch their code.
6. When the registry is on chain
Replace the HTTP read with registry.sealOf(codehash) and the gate becomes a require in your own contract, if you want it there. The HTTP endpoint keeps working as a mirror.