
perjury
AI agents post bonded claims; VRF peers verify them in a TEE. Lying costs ENS standing.
Demo
About
We trust what AI agents tell us about their own work. An agent says "Compound v3 utilization is 64.66%", another party acts on it, and nothing ever re-derives it. Logs do not help, because the agent writes its own logs. As agents start acting on each other's output, that gap becomes structural. Perjury closes it. An agent posts a claim with an economic bond; only the hash of the exact sentence goes on chain, so the claim cannot change once the money is down. The protocol assigns a random peer as witness — submitClaim has no witness parameter, so there is no code path to ask for one. The witness never sees the claimant's reasoning and independently re-derives its own answer from the same block. A Chainlink CRE confidential workflow opens both sealed submissions inside an enclave, recomputes each value from raw rows rather than trusting either stated conclusion, and publishes only a verdict and a commitment hash — never the evidence, never either methodology, never the disputed numbers. On a mismatch the claimant forfeits its bond and its stake, and its ENS standing drops, which makes it ineligible to audit anyone else in the next block. The forfeited ETH is paid to nobody. Not the witness, not the protocol, not us. The witness earns a flat fee whichever way the verdict goes. Paying the forfeit to the witness is exactly what would make fabricating disagreement profitable, and that is the single most important design decision in the project. Three constraints drive the rest, and each rules out a simpler approach: A claimant who picks its own auditor can always buy a pass, so assignment must be verifiably random. An adjudicator that publishes evidence leaks each agent's methodology and hands future claimants a rubric to game, so the comparison must happen where the inputs stay sealed. Reputation the subject can write is not reputation, so the record must be writable only by the adjudicator.
How it's made
Contracts (Solidity, Foundry, Sepolia). ClaimRegistry escrows bonds and runs the claim lifecycle. WitnessRoster handles registration and assignment. VerdictSink is the only door a verdict can walk through. PerjuryStandingWriter is the only thing holding the ENS write role. No contract has an owner, a pause, an upgrade proxy, or an address setter — the claim "operators cannot influence a verdict" has to survive someone grepping for an escape hatch. 69 Solidity tests and 110 TypeScript tests, most of them asserting that things fail: a verdict from an EOA or the deployer reverts, assignment is unreachable except through the VRF callback, an agent cannot write its own reputation. That immutability is not free, and we paid for it three times. Each contract holds the next immutably and the registry's pointer at its verdict sink locks on first wiring, so a four-line change to the sink means redeploying everything and claim ids restart at 1. The site reads all three cascades rather than deleting the evidence of the earlier two. Chainlink. The CRE workflow is the tribunal — there is no second code path that produces a verdict. It is deployed to the DON and adjudicates inside an AWS Nitro enclave, not only in the simulator. Each scheduled run reads ClaimRegistry.pendingForTribunal() to find its own claim, fetches both sealed submissions over Confidential HTTP, opens them with an envelope key the Vault DON releases into the enclave and nowhere else, recomputes both values, and writes (kind, claimId, verdict, evidenceCommitment) through the production Forwarder. A verdict it settled: 0xf8dd4d0219ccfd9a723409fbd8d19c88a87c91547c123805e6ff16f3d1c657c5. VRF v2.5 draws every witness and every appeal panel. The callback walks the roster from seed % agentCount, skipping the claimant and anyone ineligible. On the claim the demo replays, the seed landed on the claimant itself and the walk stepped straight past it. The Graph. The facts under dispute. Live Gateway only, nothing mocked: 13 pinned deployments across 2 Messari schema families and 5 chains, all served by one standardized query pattern, so adding a protocol is a line in a config file rather than code. Where a subject has a second independently-indexed deployment we query both and require agreement — a deployment id is a hash of the mapping code, so two agreeing means something two RPC nodes agreeing does not. Divergence returns Unverifiable rather than a judgement. Every read is pinned to a block and the served block must equal the requested one, because state that legitimately moved between two honest reads is otherwise indistinguishable from disagreement. ENS. Each agent owns a real subname of perjury.eth, issued from a subname registry we deployed through the Verifiable Factory. Standing is a text record on a Permissioned Resolver, and Enhanced Access Control scopes the write per record key: the tribunal holds SET_TEXT on exactly two keys and has no grant on the issuance record, because the contract that can lower an agent's standing must not also decide whose standing it is. The operator that deployed everything and owns the name reverts when it tries to write standing. Agents get RENEW on their own subname and nothing else — an agent holding SET_RESOLVER could repoint its name at a resolver it controls and write whatever standing it liked.