Moolam

ஆவணங்கள்

Proof

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

This page is for a judge with ten minutes. Every row is one claim, the screen that shows it, the file that does it, the test that holds it, and the transaction on Monad where there is one.

Nothing here is planned work. Everything in these tables ships today, on Monad mainnet, chain 143. Checked on 2026-09-22: every link on this page answered, every file is in the repo, every test name is in the suite, and every transaction was read back from Monad by its hash and is recorded in proofs/ or in the attack transcript that names it. Where a claim is smaller than it looks, the row says so, and what is deliberately not claimed is its own section at the bottom.

The contracts, the receivers the policy lists today, and their Sourcify matches are on the Introduction. The long version of any row is in Architecture, the Threat model or the API pages.

The track: trust, identity and AI infrastructure

Track 04 is "Trust, Identity & AI Infrastructure". The program says: "AI has made identity, provenance, data ownership, and agent trust urgent infrastructure problems." One of its examples is "Provenance for generated media that survives re-encoding". Moolam is that example.

The grand champion is "The best build of Metropolis." The program's own FAQ says: "Judges need to be able to verify what you built during the six weeks." This section answers that sentence.

ClaimSee itFileTest or runOn Monad
A primitive, not a platform feature. Four contracts, no upgrade proxy, ownership renounceable, and the agent identity belongs to a registry Moolam did not deployContractspackages/contracts/src/MoolamRegistry.soltest_renouncingOwnershipLocksOutRemoveReceiverAndPauseForeverRegistry 0xa191…80C0, Sourcify match
A passport survives re-encoding. Six mangled copies of one picture and a copy stripped of all metadata resolved to the same passport. The mirrored copy came back 0 of 64 bits apartVerify an imagepackages/verifier/src/fingerprint.ts, dihedral.ts, match.tsnpm run prove sections 2 and 3, saved in prove-it.txt; 360 copies and 0 false positives in robustness.txtRegistration 0x599b…5834
The holder's statement on how AI may use a picture is a dated public record, appended and never edited. Thirteen pictures carry oneMonsoon passport, "How AI may use this picture"packages/contracts/src/MoolamConsent.sol, packages/web/app/api/consent-at/route.tstest_consentAtAnswersBeforeOnAndAfterEachWrite, invariant_anEntryOnceWrittenNeverChangesStatement 0x79d4…4b61, block 105833742
The day scrubber asks the chain what was in force on a past day. One consentAt call per day landed on, not today's answer with an old date printed over itThe same passport pagepackages/web/components/passport/ConsentPanel.tsxconsent-scrubber.test.ts, "hands back the statement the chain says was in force, with the moment asked"Consent register 0x1151…1277
A picture can be registered sealed: the chain commits to the file's SHA-256, Moolam pins one small document and keeps no copy, and only the holder can publish it later, with exactly the registered bytes. The first one was unsealed by its holder four minutes after it was registeredOld but strong, sealed then published by its holderpackages/verifier/src/sealed.ts, packages/verifier/src/unseal.tsattacks-sealed.test.ts, 14 of 14, and the live half, both in pass-3.txt; the unseal in sealed-passports.txtRegistry 0xa191…80C0, registered in block 107,034,322. The unseal changes nothing on chain
A challenge costs a bond, only the named resolver settles it, and the money leaves by a pull paymentDisputespackages/contracts/src/MoolamRegistry.soltest_flagHoldsTheBond, invariant_balanceCoversEveryLiabilityThree refusals sent on mainnet: InvalidBond, NotResolver, NothingToWithdraw
An edit is a child passport with a parent link, not an overwrite. The original stays the root of its treeEdits and lineagepackages/contracts/src/MoolamRegistry.sol, packages/indexer/src/tree.tstest_appendEditRecordsTheChildAndMintsToTheParentOwner; the indexer test "keeps the original as the root all the way down a two level edit chain"Edit 0xbb12…dbf4
An agent's identity is an ERC-8004 token on Monad's canonical registry. Moolam reads ownerOf and can never mint, revoke or edit oneAgent 10249packages/contracts/src/MoolamRegistry.soltest_aRealAgentIsMintedAndOwnedByTheWalletThatRegisteredIt, a fork test against the live registryERC-8004 0x8004…a432
The attacks were executed, not described. Of the twelve, eight run twice each, as a read and then as a real transaction, and four are refused before any transaction exists, as their files say. Eight more against the consent register, eight more on a mainnet fork, and twenty-three on sealed pictures: fourteen on the verify service's routes and nine on the live serviceThreat modeldocs/security/attacks/, consent-attacks.txt, pass-2.txt, pass-3.txtnpm run prove section 5, 12 of 12 refused; npx vitest run test/attacks-sealed.test.ts, 14 of 14; npm run attack:pass3Passkey replay refused, attestation from a stranger refused
The private re-check was attacked too. Twenty-eight attacks on the verify service's link, status, delete, prepare and sweep paths, and twelve checks against the live service and the sealed receiver on mainnet. None got through where it should have been refused; one, the sweep deleting a 49 hour old copy with no passport, landed as designedThreat model, "The private re-check"packages/verifier/test/attacks-private.test.ts, packages/agents/scripts/attack-pass-4.ts, pass-4.txtnpx vitest run test/attacks-private.test.ts, 28 of 28; npm run attack:pass4, exit code 0Reads only, at block 107,820,614: a stranger's report to the sealed receiver (off the policy since 2026-09-26) reverted InvalidSender, and a stranger's attest reverted NotReceiver
Every promise carries an invariant, and the invariant names the file that holds itThreat model, entry pointsdocs/security/threat-model.mdMoolamRegistry.invariants.t.sol, MoolamConsent.invariants.t.solRan against the deployed bytecode in the fork suite, fork-tests.txt

The bounty asks for "meaningful use as an orchestration layer", "blockchain plus external API, data source, LLM or agent", and "a successful CLI simulation".

ClaimSee itFileTest or runOn Monad
The workflow orchestrates, it does not read a feed. A log trigger fires on a registration, the workflow reads the passport from Monad, fetches the picture over HTTP, decodes the JPEG and recomputes the fingerprint in the sandbox, then writes the verdict back on chainChainlink CRE workflowpackages/workflow/moolam-verifier/workflow.ts, decode.ts, phash.tsMoolamReceiver.t.sol, 16 testsPublic receiver 0x4aD6…Aa95, where the simulator's runs write since 2026-09-27; 0x0d69…ff04, where Chainlink's network writes, listed again on 2026-10-02 in 0x446c…ff9f; the re-checks before 2026-09-26 sit under it too
The workflow ran on Chainlink's network, and ten nodes agreed. The first network verdict: passport 0x793a…5782 was registered at 07:23:26 UTC on 2026-10-02, ten Chainlink nodes recomputed its fingerprint, distance 0, matched, and the verdict was written at 07:23:42 UTC, 16 seconds later, to the Keystone Forwarder. The deployment is moolam-verifier, workflow ID 00c4dd797775bb465fff638ab5171b19a35ed11d4513eb4890661935d4801890, owner 0xf072a8c620bfc818875736e3f2d3a2a339c06584, verdict step onlyChainlink CRE workflow, "On Chainlink's network"packages/workflow/moolam-verifier/workflow.tsRead the verdict transaction on MonadVision: its to is the Keystone forwarder, and the passport page says so under the verdictRegistered in 0x162c…feaa, verdict in 0x760d…2882, block 109,833,597, to the Keystone forwarder 0x76c9…5E62
A successful CLI simulation, seventeen times. Every one of the seventeen real pictures on the registry carries a re-check delivered on chain, with its recomputed fingerprint and its bit distanceMonsoon passport, "Second opinion"rechecks.txtverify-recheck.test.ts, "reads the live shape: one re-check that matched, with its distance, day and receiver"Re-check 0x59e6…80fa, distance 0
The receiver accepts this workflow and nothing else. It is pinned to the workflow author and the workflow name, and a report from any other sender is refused before it is readPolicy and receiverpackages/contracts/src/SimulationReceiver.sol for the simulator's runs, and packages/contracts/src/MoolamReceiver.sol for Chainlink's networkMoolamReceiver.t.sol: test_aReportCarryingAnotherAuthorIsRefused, test_aReportCarryingAnotherWorkflowNameIsRefused, test_aReportFromAnyOtherAddressIsRefused. For the receivers written to since 2026-09-27, SimulationReceiver.t.sol: test_aReportCarryingAnotherWorkflowNameIsRefusedByThePin, test_theSendingWalletCannotSkipTheForwarder, test_aReportFromAnyOtherOriginIsRefused; and SimulationReceiver.fuzz.t.sol: testFuzz_anyOriginOtherThanTheSendingWalletIsRefusedReport from a fake forwarder refused
The delivery label is honest. Each verdict says which forwarder delivered it, and a verdict says network forwarder only when Chainlink's Keystone forwarder delivered it, as the first one did on 2026-10-02. Every earlier one says simulation forwarder rather than claiming a network reached consensusThe same passport page, under each verdictpackages/web/components/passport/Attestations.tsxattestation-delivery.test.ts, "says a simulation run when the report came through the simulation forwarder" and "names the workflow rather than claiming an independent network"Simulation forwarder 0x9eF6…784d beside the production Keystone forwarder
Confidential Workflows, Chainlink's CRE release of 7 August 2026 (CLI v1.29.0, the release that also added Monad mainnet support), run as a spike. A private file nobody can fetch from a public gateway was pulled with a credential inside the handler, fingerprinted there, and matched the fingerprint on chain at 0 bits. Only the verdict crossed outNo screen. This one is a spike, and the release is on Chainlink's CRE release notespackages/workflow/moolam-sealed-spike/workflow.ts and its README.mdcre workflow simulate moolam-sealed-spike, and a wrong credential ends the run at the link call with a 401 and no fingerprintNothing. No transaction, no --broadcast, no receiver. The simulator says of itself: "The simulator is not a real TEE, and is meant to debug." One machine, no hardware isolation, no node consensus
A Chainlink confidential workflow re-checked a picture that has never been published. moolam-sealed-verifier, registered with handlerInTee, opened Moolam's 512 pixel private copy through a link the verify service mints only under a queue claim, recomputed the fingerprint and wrote only the verdict: distance 0, matched. It ran in Chainlink's simulator with --broadcast, which is one machine and not a real enclaveKanchipuram Silk Loom at First Light, "Second opinion", marked "Private re-check"packages/workflow/moolam-sealed-verifier/workflow.ts, private-copy.tscre workflow simulate moolam-sealed-verifier --broadcast, recorded in sealed-passports.txt; sealed-private-copy.test.tsReport 0xa38f…c954, block 107,834,613, on this passport, and the first run's report 0xdc18…0bef, block 107,817,793, both through the simulation forwarder
The chain says which workflow wrote a verdict. Private re-checks go through a second receiver pinned to moolam-sealed-verifier, and the registry stores the receiver with every attestation, so a private verdict can be told from a public one without asking MoolamThe same passport page, "Written by"packages/contracts/script/DeploySimulationReceivers.s.sol, packages/contracts/deployments/simulation-receivers-monad-mainnet.jsonnpm run attack:pass4, 8b reads the pin back and 8d the row's receiver, in pass-4.txt, run against the older sealed receiverSealed receiver 0x52b8…57f6, listed by the policy after its 24 hour wait in 0x0e1e…457d; the first two private verdicts carry the older 0x7b9e…E45A (off the policy since 2026-09-26)
A copy of the public workflow cannot write a verdict. Since 2026-09-26 simulated reports have two receivers of their own that accept a report only in a transaction signed by Moolam's CRE wallet, fixed at deployment with no setter. On a mainnet fork, the Monsoon report sent through Chainlink's real mock forwarder wrote an attestation from the CRE wallet and nothing from a stranger, and a replay wrote nothingChainlink CRE workflow, "The receiver, and what a simulation needs"packages/contracts/src/SimulationReceiver.sol, simulation-receivers.txttest_theSameReplaysFromAnyOtherWalletWriteNothing on the fork; testFuzz_anyOriginOtherThanTheSendingWalletIsRefused, 512 runsPublic receiver 0x4aD6…Aa95 and sealed receiver 0x52b8…57f6, Sourcify match, listed in the policy since 2026-09-27 14:18 UTC in 0xac64…0bfb and 0x0e1e…457d; the two MoolamReceiver contracts came off the policy on 2026-09-26, history kept, and the public one has been listed again since 2026-10-02
The re-checks run themselves. Since 2026-09-27 15:12 UTC the re-check runner takes new registrations and requested re-checks every two minutes, at most 5 runs a round and 40 a day, and runs the workflow with --broadcast. Its first two verdicts were written with nobody pressing anything, 451 and 832 blocks after each picture was registered, and both matchedChainlink CRE workflow, "How a run is driven today"packages/recheck-runner/, rechecks.txtThe live runner on its server; the caps are "The guards" in packages/recheck-runner/README.mdReport 0x3771…e24b, block 108,499,297, 1 of 64 bits, and report 0x35c1…4c1a, block 108,505,240, 0 of 64 bits, both from the CRE wallet through the simulation forwarder to the public receiver 0x4aD6…Aa95

Envio: depth of use

The Envio bounty judges six things: multichain use, a non-trivial schema, derived or aggregated entities, live and correct data, originality, and craft. The program's public page gives only the bounty's title, so these six are in our words, not quoted. Moolam indexes one chain, Monad mainnet. The rows below answer the other five.

ClaimSee itFileTest or runOn Monad
Derived entities, not a log mirror. Creator, Generator with its trust score, CreatorDay, DailyStats, GlobalStats, ConsentEntry, and the flattened statement on every PassportEnvio indexerpackages/indexer/schema.graphql, packages/indexer/src/trust.ts, packages/indexer/src/day.ts, packages/indexer/src/consent.ts47 indexer tests, saved in indexer-tests.txt; "splits the daily counters by UTC day while the global totals keep adding up"Watches all five contracts it reads from their deploy blocks
inheritedDisputed: an edit made after its parent lost a challenge is marked, so a reader does not have to walk the tree to find outExplore, the Disputed chippackages/indexer/src/tree.ts"gives an edit made after its parent lost a challenge the inherited mark", and "marks every edit already made from a passport when its challenge is upheld"No dispute has ever been opened on mainnet, so this is held by the tests and by attack 6 on a mainnet fork in pass-2.txt
Working, live, correct. This query was run against the hosted endpoint on 2026-09-22 and the answer is below, untouchedGraphQLpackages/indexer/src/EventHandlers.tsThe 47 tests aboveOn that day the fourteen re-checks then in rechecks.txt were fourteen of the fifteen attestation rows the index returned, the fifteenth being an earlier delivery; two more were added on 2026-09-23
The app reads the index, never a fixture. Explore, its AI-use filter, Agents, and the film's own counts all read live and say so when the index does not answerExplore and Agentspackages/web/components/explore/query.ts, packages/web/lib/data/passports.tsexplore-consent.test.ts, "says how many pictures carry a statement, counted by the index itself"; index-retry.test.tsThe registry and the consent register, read through the index
query ProofToday {
  GlobalStats {
    passports
    creators
    generators
    attestations
    disputes
    consentStatements
    passportsWithConsent
  }
}
{ "passports": 37, "creators": 4, "generators": 2, "attestations": 15,
  "disputes": 0, "consentStatements": 13, "passportsWithConsent": 13 }

Privy: beyond login

The bounty asks for use "beyond login", a demo that must "clearly show the Privy-powered function", and gives a bonus for several Privy features. Moolam uses five: embedded wallets, passkeys, gas sponsorship, session signers under a policy, and server wallets with a key quorum.

ClaimSee itFileTest or runOn Monad
Embedded wallets. An email code creates an account on Monad with no seed phrase and no extensionRegister an imagepackages/web/components/providers/PrivyProvider.tsx, packages/web/components/providers/WalletProvider.tsxwallet-gate.test.ts, wallet-returning.test.tsCreator 0x85a8…39a6
Passkeys, bound on chain and checked by Monad's P-256 precompile at 0x0100. Both user presence and user verification are required, so only someone who touched the sensor can make a passportThe same screen, "Use this device's unlock"packages/web/lib/passkey/webauthn.ts, verify.ts, packages/contracts/src/MoolamRegistry.solparity.test.ts, "agrees field for field on one signature"; test_bindPasskeyRefusesAnAssertionWithoutUserVerificationBind 0x34cf…fffa, sponsored
Gas sponsorship on every write. The recorded run printed "sponsorship: on, the app paid the gas, not the creator's wallet"Every receipt, where "Network fee" reads "Paid by Moolam through Privy"packages/web/components/studio/Receipt.tsxprivy.txtThe two passkey sends below went through the ERC-4337 EntryPoint from a bundler, so the creator paid nothing
Session signers under a policy. A creator grants the editing app one signer, held to appendEdit on the Moolam registry and nothing else. Revoke it and Privy refuses the same call before it reaches Monad"Allow edits from this app", on any passport you hold. The walkthrough is in Edits and lineagepackages/agents/src/privy/sessionSigner.ts, packages/verifier/src/edit/packages/web/test/attacks/duplicate-child.test.ts; the revoked signer is refused in privy.txt step 7Edit signed by the session signer 0xbb12…dbf4
Server wallets with a key quorum: an agent transacting from a wallet built on Privy. The demo agent's key lives in Privy's enclave under a policy that allows register on one contract on chain 143 carrying no MON, and EIP-712 signing over that same contract. It signs the generator half of every picture it drawsAgent 10249, and the studio's "Make one with the agent"packages/agents/src/privy/serverWallet.ts, generatorSigner.ts, policies.tsprivy.txt steps 3 to 5: the agent registered under policy kvq9627q5dfpv90xegi5h1cj, and both a MON transfer and an appendEdit came back policy_violation with nothing signedRegister by the agent 0xbf6a…9079
Two transactions a person really made, with a real passkey, on 20 September 2026. One from a passport page on an existing picture, one from the studio at the moment of makingThe passport that was stated onconsent-statements.txtRead back from the chain with cast call consentOf the next dayHolder's statement 0x4601…5361 in block 106391876, and the studio's statement 0xfd6d…6d74 seven seconds after its registration

Monad itself

ClaimSee itFileTest or runOn Monad
Four contracts on chain 143, all verified through Sourcify, deployed by one repeatable scriptIntroductionpackages/contracts/script/deploy-dryrun.txtRegistry, Policy, Receiver (off the policy 2026-09-26, listed again 2026-10-02), Consent
The P-256 precompile at 0x0100 is what makes a passkey a first class signer here. No server checks the WebAuthn assertion, and it cannot be added after the factWhy Monadpackages/contracts/src/MoolamRegistry.sol, through OpenZeppelin's WebAuthn librarytest_registerRejectsAPasskeySignatureFromAnotherDevice, test_registerRejectsAPasskeySignatureOverAnotherPassportEvery registration transaction in this page's rows
Gas, measured rather than estimated. The live registration cost 376,128 gas, and Monad bills the limit declared rather than the gas usedWhy Monadgas.txtforge test --gas-report; a first statement measures 117,337 gas and a later one 91,036The 376,128 gas registration
Sub-second blocks, measured on one real pair of sends. The studio's statement landed 23 blocks, seven seconds, after the registration it belongs toRegister an image, where the receipt prints the milliseconds it measured in the browserpackages/web/components/studio/Receipt.tsxstudio-render.test.ts pins the receipt's confirmation line in every languageRegistration at block 106392736, statement at block 106392759
A live registry, not a demo fixture: 37 passports, 4 creators, 2 generators, 13 statements todayExplorepackages/web/lib/data/passports.tsThe query above, run on 2026-09-22Every row reads from the four contracts

What is deliberately not claimed

  • No copyright proof. A passport proves who registered first. It does not prove who created the picture and it does not prove who owns the rights to it.
  • No compliance claim. Registering a picture here does not make a provider or a deployer compliant with any law. Rules and standards sets what Moolam does beside what the C2PA specification and the EU texts actually ask for.
  • Network consensus covered the verdict step only until 2026-10-07. Chainlink's network has run that step since 2026-10-02, and the first verdict is in the table above. Every re-check before it came from Chainlink's simulator run with --broadcast, one machine and no quorum, and the passport page says so under each verdict. The look-alike step is in the network workflow from 2026-10-07, with the verify service's look-alike routes, its Google web check on the hosted service, and the hosted index rebuild that lets the live site's marks and counts see the network flag.
  • No watermark. Moolam writes nothing imperceptible into the picture. A product that needs machine-readable marking in the file itself still needs a watermarking layer beside this one.
  • No crop resistance. Cutting about ten percent off each edge breaks both fingerprints: 0 of 24 copies matched in the sweep. Fingerprints has the numbers.

Try to break it

Reading a refusal is weaker than watching one. Try to break it sends eleven of these attacks, and one control that has to pass, from the browser to the deployed contracts on Monad mainnet as eth_call, so the refusal that comes back is the contract's own and nothing is signed or spent.

The transcripts behind every refusal are in docs/security/attacks/, and the full sessions are in prove-it.txt and consent-attacks.txt.