Docs · Tutorials

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.