The seal
What gets sealed, why it is a hash of bytecode and not an address, and what that means for every deployment of the same code.
Bytecode, not address
A seal is written against keccak256(runtimeBytecode). Not the contract address, not the source, not the deployer.
Three consequences follow, and all three are deliberate.
The seal follows the code. Every contract on Robinhood Chain with that exact runtime wears it. Deploy the same token twice, both are sealed. Deploy it on another chain, the hash is the same and a registry there could honour it.
One byte changed, no seal. A fork with one line edited has a different hash and starts from nothing. That is what makes the badge worth reading: it cannot be inherited.
The seal cannot see state. Bytecode is the same for every deployment, so the seal knows nothing about which address is the owner of this one, what the constructor received, or where the liquidity is. Two deployments of the same sealed code, one honest and one not, wear the same seal. Limits says more.
What is in a seal
| Field | What it is |
|---|---|
hash |
keccak256 of the runtime bytecode, lower-case hex. The key. |
name, symbol |
What the submitter called it, as the seal shows it. Not verified against the token. |
address |
The deployment the review was matched against, if any. Null for a review of undeployed bytecode. |
commit |
The git commit the source was read at. |
contract |
The contract name inside the source that matched. |
compiler |
The Solidity version, from the artifact. |
checks[] |
Eight entries: id, title, pass (true, false or null for not run), note (the evidence). |
passed |
How many are true. |
review |
The auditor's signed text, or null. |
reviewModel |
Which model wrote it, or why it was skipped. |
auditor |
The address that signed. |
signature |
Over the digest below. |
proven |
signed or zkvm. |
x |
The post id on X, if one went out. |
createdAt |
Unix milliseconds. |
The digest
The auditor signs, with personal_sign semantics (an EIP-191 message), the keccak of this string:
zkcheck:v1
<hash, lower-case>
01:1,02:1,03:0,04:1,05:1,06:1,07:-,08:1
<keccak256 of the review text, or 0x if none>
The answers line lists each check id with 1 for pass, 0 for fail and - for not run. Anyone can rebuild the string from the seal's public fields and recover the signer. Verify a seal yourself does it in twenty lines.
Runtime versus creation
eth_getCode returns runtime bytecode: what runs when the contract is called. Creation bytecode is the constructor plus the runtime, and it is gone after deployment. A seal is about what runs, so it hashes the runtime. If you paste bytecode for an undeployed contract, paste the runtime (deployedBytecode in a Foundry or Hardhat artifact), not bytecode.
What is set aside when matching
Matching the compiled artifact to the chain is not a plain equality, because two honest builds of the same source can differ in two places.
Metadata. The compiler appends a CBOR block holding a hash of the source files and the compiler version. Because the hash covers file paths, a build in /home/a/token and a build in /app/token differ there. zkCheck strips the block on both sides before comparing. The seal's hash, though, is over the full on-chain bytecode, metadata included, because that is what eth_getCode returns and what anyone else will hash.
Immutables. A variable declared immutable is set in the constructor and inlined into the runtime. The artifact has zeros in those slots; the chain has the value. The compiler reports where they are, and zkCheck zeros both sides there.
Everything else must match exactly. Optimizer runs, via_ir, the compiler version, library addresses: any difference changes the code and the match fails. Why bytecode does not match is the troubleshooting page.