Moolam

Developers

Architecture

இந்தப் பக்கத்தில்

Three diagrams: what the pieces are, what happens when one image gets a passport, and what the contracts depend on.

System overview

Five people or programs touch the system and each one enters through a different door. The creator binds a passkey (bindPasskey) and registers, and states how AI may use the picture. The generator agent registers on the creator's behalf, with both signatures. An editing app appends edits through a Privy session signer. Anyone verifying uploads a copy to the verify service and never touches the chain at all. On chain, MoolamRegistry reads the P-256 precompile for passkeys, the ERC-8004 Identity Registry for agent ownership, and VerifierPolicy for who may attest, while MoolamConsent reads the registry for who holds a passport. Off chain, the Chainlink CRE workflow re-fetches and re-fingerprints, Envio indexes the events, and the verify service reads passports out of Envio and statements straight off the consent register.

Chainlink's verdicts reach the registry two ways. A verdict from Chainlink's network goes through the Keystone Forwarder to MoolamReceiver, and only those can light a passport's trust mark. A test run in Chainlink's simulator goes through the simulation forwarder to the SimulationReceiver pair, which also checks that Moolam's CRE wallet signed the transaction. The sealed workflow reads a private copy through a link the verify service mints.

The drawing reads from top to bottom. Rounded boxes are people and agents, solid boxes are contracts on Monad mainnet, and dashed boxes run off chain.

படம் வரையப்படுகிறது

Main sequence: a generated image gets a passport and is verified

Everything before the register call is preparation that costs no gas: the fingerprint, the C2PA manifest, the four IPFS pins, and the EIP-712 digest read back from the contract. Then two signatures over that one digest, the creator's passkey and the agent owner's wallet, and one transaction that checks both. The registration event is what wakes the Chainlink workflow, which fetches the image itself, recomputes the fingerprint and writes the result back through Chainlink's Keystone Forwarder to MoolamReceiver. On Chainlink's network a quorum of nodes must produce the identical verdict before a report is signed, and the first one did on 2026-10-02: ten nodes, distance 0, written 16 seconds after the passport was registered (transaction 0x760dcb5e…2882). A run in Chainlink's simulator with --broadcast is one machine and no consensus. It goes through the simulation forwarder to a SimulationReceiver, which takes it only in a transaction Moolam's CRE wallet signed. The passport page labels each verdict by the forwarder that delivered it.

படம் வரையப்படுகிறது

Verification of a copy later runs entirely off chain: anyone uploads a file to the service, the service computes the eight rotated and mirrored fingerprints, searches the index, and returns the best passport with its attestations, its edit chain and a confidence score.

A statement about AI use, and the day query

A creator's answer to "may AI train on this" is written twice in the same minute and read back much later. The service writes it into the signed C2PA manifest and the pinned metadata before the passport exists, because a manifest is signed once and cannot be added to. The chain half waits until the registration is confirmed, then goes out as a second sponsored transaction from the creator's own wallet. If that second send fails, the passport stays registered and the statement can be written later from the passport page.

The second half of the drawing is the question a label inside a file cannot answer. A reader asks the register what was in force on a given day, and gets that day's entry rather than today's.

படம் வரையப்படுகிறது

Contract dependency graph

MoolamRegistry is built out of OpenZeppelin v5.6.1 and reads two contracts it does not own. It holds IVerifierPolicy as an immutable address set at deployment and Monad's ERC-8004 Identity Registry the same way. Every receiver contract inherits Chainlink's ReceiverTemplate verbatim, vendored under src/vendor/chainlink/ so it can be diffed against Chainlink's published source. The SimulationReceiver pair in use since 2026-09-27 takes onReport only from Chainlink's simulation forwarder and only in a transaction Moolam's CRE wallet signed. MoolamReceiver takes it from the Keystone Forwarder and from the workflow it is pinned to, which is how Chainlink's network writes. It came off the policy on 2026-09-26 and went back on the list on 2026-10-02 at 07:08:18 UTC, in transaction 0x446c3051…ff9f. Its sealed twin has been off the list since 2026-09-26. MoolamConsent depends on nothing but an IERC721 view: it holds the registry address as an immutable set at deployment and asks it ownerOf, which is the whole integration. The arrow points one way, so the registry does not know the consent register exists.

படம் வரையப்படுகிறது

How the app reads the chain

Every chain read a page makes happens on the app's server, not in the browser, so one endpoint answers for every visitor. Two endpoints can be named. NEXT_PUBLIC_MONAD_RPC_URL is the public one and is the only address the browser is ever given. MONAD_RPC_URL is optional and secret: a dedicated endpoint, such as a QuickNode one, whose address carries its own access token. When it is set, the server tries it first and falls back to the public endpoint, so a rate-limited minute on either side is a slower page rather than an error. It is read on the server only, it must be an https URL or the app refuses to start, and the one line a page prints when a read fails has every address taken out of it first.

What is immutable and what can change

  • MoolamRegistry has no upgrade path. Records, edits and attestations are only ever added. The owner can pause new writes and rescue tokens sent by mistake; the owner cannot edit or delete a passport.
  • MoolamConsent has no upgrade path and no owner at all. Statements are only ever appended, so a new one supersedes an old one without hiding it, and nobody can pause it or take it back.
  • VerifierPolicy is the only mutable piece: the list of receivers allowed to attest, the dispute resolver, the treasury and the bond. Every change is queued and executes 24 hours later, publicly, except removing a receiver, which is immediate so a compromised verifier can be cut off. Two changes ran through that queue on 2026-10-02: MoolamReceiver was listed again at 07:08:18 UTC, and the treasury was set to the burn address 0x000000000000000000000000000000000000dEaD at 07:27 UTC (transaction 0x45700954…371d), so a rejected challenge's bond is burned.
  • The ERC-8004 registry is Monad's canonical deployment. Moolam only reads it.

The exact function signatures, events and errors are in the API reference. ABIs live in packages/contracts/abi/.