VAULT
브라우저에서 비밀번호로 파일을 암호화·복호화하며 데이터는 절대 업로드되지 않습니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A certificate of origin for every AI response.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Signed receipts for AI responses, anchored on Monad
The host signs what it served. Monad holds the proof. Open verifiers grade the host. You decide whose grades count.
A receipt proves who served which bytes and what they claimed. It doesn't prove which weights ran.
You call an open-weight model through someone else's host, and the text comes back with no proof of who served it.README 전문 보기 ↗The host signs what it served. Monad holds the proof. Open verifiers grade the host. You decide whose grades count.
A receipt proves who served which bytes and what they claimed. It doesn't prove which weights ran.
| 💬 Ask, get a receipt | 🔎 Check any receipt | 🧾 A live receipt | 🖥️ Host profile | 📚 Docs | 📜 Spec | 📊 Report |
|---|---|---|---|---|---|---|
| /app/#ask | paste it, checked on Monad | first on mainnet | agent 10278 | gitbook | SPEC.md | REPORT_v0 |
You call an open-weight model through someone else's host, and the text comes back with no proof of who served it.
The hosts don't all serve the same thing. On 26 Sep 2026, OpenRouter listed 735 open-weight endpoints. 39% don't state their precision and 15% declare 4-bit. GLM-5.3 alone has 37 endpoints: 16 state no precision, and output prices run from $1.19 to $8.80 per million tokens. The same weights score differently depending on who serves them. Olly measured DeepSeek V4 Flash at 90% on GPQA through DeepSeek's own API and 75% on another host. Cline measured GLM-5.2 at 74.2% on one host and 61.8% on default routing.
The checks that exist stay where they were made. A router's grades only work inside that router, and a lab's verifier only covers its own models. Nothing travels with the answer.
Assay is the part that travels. Every response gets a receipt. Hosts can't deny what they signed, verifiers grade hosts in public against the lab's own API, and anyone can check both without trusting us.
We measured one difference ourselves on 8 Oct. Sixteen hosts on OpenRouter answered our Kimi K2.6 checks, and on tool calling all of them matched Moonshot's own endpoint, 32 of 32. Then we capped the answer at 16 tokens. Three of those hosts ignored the cap in 59 of 60 trials, returned about 2,000 tokens, and were billed 70 to 126 times what Moonshot charged for the identical request. They ignored it even with OpenRouter's require_parameters on, so it's the provider and not the router. Method and numbers. The raw file isn't public yet. Its sha256 is in that write-up, and the file itself goes public on 25 Oct with the hosts' names and any replies, after the 7 days we give every host. (We first wrote 15 Oct, saying the hosts had their logs on 8 Oct. They didn't: the logs went out on 18 Oct. The write-up has the correction.) One cap trial per host is already in our public 8 Oct grading bundle, so a reader can find the names there today; we chose not to repeat them before the hosts have replied.
| What | Evidence | |
|---|---|---|
| ✅ | Receipts signed by two hosts and anchored on Monad mainnet (Gemma 4 31B, and Kimi K2.6 from Moonshot's own endpoint) | docs/deployments.md |
| ✅ | A requester's browser passkey co-sign, verified onchain by Monad's P256 precompile, and replayed byte for byte in CI | tx 0x4377e096… · MainnetReplayTest |
| ✅ | Grades onchain against the lab's own endpoint: 21 on mainnet (17 of them Kimi K2.6; Gemma re-graded 12 Oct), 43 on testnet (GLM-5.3 and Gemma) | docs/evidence/ |
| ✅ | Paid use: Kanmani's escrow paid host 10278 per verified receipt for two jobs on mainnet (10 receipts, 0.10 USDC). MonadGuard verifies our mainnet receipts in its nightly CI; Mida built and merged their integration | issue #4 · docs/interop/ · PR #6 |
| ⚠️ | Every grade so far comes from Assay's own verifier. Anyone can register and post, and readers pick whose grades count, but nobody else has posted yet | VerifierRegistry.registerVerifier |
| ⚠️ | Chainlink CRE re-checks real mainnet grades, but as simulation broadcasts, not a deployed DON. The first attestor accepted any simulator broadcast, so it's retired; v2 only accepts reports sent by our relayer and writes each grade once | cre/ · CreAttestorTest |
| ⚠️ | Per-app keys that never hold MON (EIP-7702 gas sponsorship) work end to end on testnet; there's no mainnet run yet |
| Mark | What it means | Checked by |
|---|---|---|
| 🟡 HOST | The host's ERC-8004 identity signed this exact response (ES256 over canonical JSON) | Your browser, against the host's published JWKS |
| ⚪ MODEL | The model the host claimed to serve | Signed into the receipt, so a false claim is a signed false claim |
| 🟣 ANCHOR | The receipt is in a batch whose Merkle root the host anchored on Monad | Monad: ReceiptAnchor checks the batch signature with the P256 precompile |
| 🩷 YOU | The person who asked co-signed the receipt with a passkey or a per-app key | Monad: WebAuthn through the P256 precompile, or ecrecover for per-app keys |
What it doesn't prove: which weights actually ran. A host can still sign a lie. With Assay that lie is signed, anchored and graded in public. Re-execution and TEE attestation are next on the roadmap.
Your prompt and the answer never go onchain. The receipt holds salted hashes, and you keep the salt.
flowchart LR
subgraph You["👤 Requester"]
APP["App or agent<br/>assay-receipts · wrap(fetch)"]
PK["Passkey<br/>Mera PRF vault + per-app keys"]
end
subgraph Host["🟡 Host"]
H["OpenAI-compatible proxy<br/>signs every response"]
UP["Upstream model"]
end
subgraph Monad["⛓️ Monad"]
RA["ReceiptAnchor<br/>P256 · 0x0100"]
VR["VerifierRegistry<br/>gradeOf(model, host, trusted[])"]
CA["CreAttestor"]
ID["ERC-8004<br/>Identity + Reputation"]
end
subgraph Trust["🛡️ Checking"]
V["Open verifiers<br/>host vs lab's own API"]
CRE["Chainlink CRE<br/>re-checks posted grades"]
IDX["Envio HyperIndex<br/>batches · keys · grades · drift"]
end
APP -->|"prompt + salt"| H --> UP
H -->|"answer + signed receipt"| APP
H -->|"Merkle root, one signature per batch"| RA
PK -->|"co-sign"| RA
V -->|"grade + evidence hash"| VR
VR -. GradePosted .-> CRE -->|"agree / disagree"| CA
RA -. events .-> IDX
VR -. events .-> IDX
ID -. ownerOf .-> RA
ID -. ownerOf .-> VR
| Building block on Monad | What Assay does with it |
|---|---|
P256 precompile (0x0100) | Host keys, cloud KMS keys and passkeys all sign with P-256. ReceiptAnchor checks the host's batch signature and the requester's WebAuthn co-signature onchain, at about 61k gas per anchor and 73k per co-sign. Two canary tests fail if the precompile ever goes missing and OpenZeppelin falls back to its ~250k-gas Solidity path. |
| ERC-8004 | Every host and every verifier is an ERC-8004 agent. Grades follow the identity (keccak256("erc8004:<chain>:<id>")), not the signing key, so rotating a key can't wipe a bad grade. The indexer counts a complaint only if its sender co-signed the receipt it cites. |
| Cheap, fast blocks | One anchor per batch: about 0.0001 MON per receipt in a 64-receipt batch, so small batches can go onchain often (every 30 seconds on the reference host). |
import { wrap, chainGradeCheck, verifyReceipt, GradeGateError } from "assay-receipts";
const HOST = "https://34-45-1-81.sslip.io/kimi"; // Assay host 10316 (Kimi K2.6) on Monad mainnet
const REGISTRY = "0x0C8603041E7d425c4DCa041680C7AF4581dDa9a1"; // VerifierRegistry on Monad mainnet
const MY_VERIFIER = "0x4BaC2Be288B5931886EeC4c555895CE6BcAB19e7"; // a verifier you choose to trust
const messages = [{ role: "user", content: "Say OK" }];
// Refuse a host before sending (or paying) unless verifiers you trust grade it "pass" against the lab's own endpoint.
// The grade is read from the chain (`client` is a viem public client for Monad), never from the host itself.
const ask = wrap(fetch, {
gate: {
check: chainGradeCheck(client, { registry: REGISTRY, model: "moonshotai/kimi-k2.6", host: "erc8004:143:10316", verifiers: [MY_VERIFIER], reference: "openrouter:moonshotai/int4" }),
allow: ["pass"],
},
});
const { json, receipt, salt } = await ask(`${HOST}/v1/chat/completions`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ messages }),
}); // throws GradeGateError, and sends nothing, if the gate says no
// Anyone, later: every check on its own, each with the exact call that reproduces it
const result = await verifyReceipt({ body: receipt.body, jws: receipt.jws, jwks, proof, root, onchain: { client, anchor }, salt, output, messages });
result.checks; // { jws, hash, kid, merkle, anchored, outputCommit, promptCommit, cosigned }
result.reproduce.anchored; // { kind: "contract-call", address, function, args } → paste into cast
@assay/receipts is the sdk/ workspace package. It is published on npm as assay-receipts (npm install assay-receipts), because the @assay scope belongs to someone else. SDK reference · Quickstart
| Contract | Address | Deploy |
|---|---|---|
| ReceiptAnchor | 0x049A73755cA3508ef3Daa4752A3406f6e00CfB13 | tx |
| VerifierRegistry | 0x0C8603041E7d425c4DCa041680C7AF4581dDa9a1 | tx |
| CreAttestor v2 | 0x71EDfF0bcd68ba2508C4B08a8606F76C5C26915E | tx |
| AssayAccount (EIP-7702 delegate) | 0x7755818dc08659D2A3A66FA3ddb1Ce636c145C91 | tx |
Verified on Sourcify (exact match). Host agent 10278 and verifier agent 10279 are registered on the mainnet ERC-8004 registry. ⛓️ The first mainnet receipt is anchored, and verifyReceipt returns true onchain. The first mainnet grade is posted too: host 10278 scored 38/38 against Google's own API. The latest, on 12 Oct, is 37/37, with Google's endpoint at 40/40 in the same run (0x91af734c…). It's a plumbing check, because the host relays that same API, so it shows the loop works on mainnet rather than measuring host quality.
A second mainnet host, agent 10316, serves Kimi K2.6 from Moonshot's own endpoint. Its grade is 32/32 against Moonshot's endpoint, and a Chainlink CRE re-check of that grade agrees onchain (a simulation broadcast, not a DON). This is a plumbing check too: the host relays the endpoint it's graded against.
Testnet stays live as the free place to try things. The app has a network switch in the top bar.
| Contract | Address | Deploy |
|---|---|---|
| ReceiptAnchor | 0x63e4F42E6d254ed6aAE735F9F4169BbFd12c1a24 | tx |
| VerifierRegistry | 0x7755818dc08659D2A3A66FA3ddb1Ce636c145C91 | tx |
| CreAttestor (v1 design, demo only) | 0xB4A1CB9e40aDa44570Ae790430C23876d460deDC | tx |
All three are verified on Sourcify (exact match). The testnet CreAttestor predates v2, so like the retired mainnet v1 it accepts any simulator broadcast; treat its attestations as demos.
| Onchain so far | Proof |
|---|---|
⛓️ First real receipt anchored: Gemma 4 31B through the reference host (agent 1962). verifyReceipt returns true | tx 0x41f73bca… |
| 📈 First grade: Gemma 4 31B on OpenRouter's Google AI Studio route, 6/6, 95% interval 60.96% to 100% | tx 0xbae5c59e… |
| 🎯 Reference grade: same model on Google's own API, 19/19, 83.18% to 100% | tx 0x137f910d… |
| 🪪 Host agent 1962 key set · verifier agent 1981 registered | 0xcfd45e43… · 0x752c6fe5… |
Both grades read warn until a host has 30 samples. The reference hosts run at https://34-45-1-81.sslip.io (testnet) and https://34-45-1-81.sslip.io/mainnet (mainnet), and anchor each batch within seconds. Every address and tx is in docs/deployments.md.
Live on Envio Cloud
Indexes every Assay contract plus ERC-8004 identity and reputation. Drift events, per-model leaderboards and key rotations are computed in handlers. The receipt page reads the batch, the key that signed that batch and the co-signs in one GraphQL query. The contract only stores a host's current key, so the indexer is the only place the old signing key lives.
Proof: indexer/ · endpoint · 24 handler tests
grade-recheck workflow
A single verifier could lie about the grade it posts. On every GradePosted (finalized), the workflow downloads the evidence, checks its sha256, recounts pass and total, and recomputes the Wilson interval. In a deployed DON every node would have to agree on that result byte for byte; these runs are one simulator. Before writing, it reads VerifierRegistry and CreAttestor at the finalized block, so it never attests a claim the registry doesn't hold, or the same grade twice. On mainnet it re-checked four real grades on CreAttestor v2 and wrote agree=true each time (38/38, 32/32, 39/39, and host 10278's 12 Oct re-grade, 37/37). These are simulation broadcasts: no DON ran, our key relayed the simulator's output, and anyone can re-run the same check. An inflated replay (claims 10/10, the logs say 8/10) returns agree=false.
Proof: docs/evidence/cre-simulate-mainnet.txt · cre/ · 31 tests
One passkey, many keys
The passkey's PRF output derives an AES-GCM key for a vault that keeps your receipts and salts as ciphertext only, per-receipt reveal keys for showing one answer to one person, and per-app secp256k1 requester keys that can't be linked across apps. Nothing derived is stored, and a second device with the same passkey re-derives it all. Per-app keys co-sign onchain with cosignK, and the host pays the gas, so a per-app address never needs funding. So far that has run on testnet; there is no mainnet cosignK yet.
Proof: web/src/lib/vault.ts · web/src/mera.ts · docs
Identity, reputation, receipts
Hosts and verifiers are ERC-8004 agents, and VerifierRegistry re-checks ownership on every grade, because an identity can be sold. The indexer counts feedback against a host only if the sender co-signed the receipt it cites, so complaints come from people who were actually served.
Proof: test_post_afterIdentityTransferred_reverts · 3 fork tests against the real registry
Same receipt format, verified both ways
MonadGuard checks the tool, Assay checks the model host that answered. Both sign ES256 over JCS with keys in a JWKS. Assay's verifier passes MonadGuard's mainnet receipts, and MonadGuard's verify-foreign.mjs passes six of ours (three on mainnet, one co-signed) with 10 of 10 checks, including a byte-for-byte JCS match. Each side pins the other's receipts as offline CI fixtures and checks that a copy with one byte flipped is rejected.
Proof: docs/interop/ · sdk/test/interop.test.ts
Proposed (PR #12): only pay for inference from graded hosts
A mandate bounds how much an agent spends. Our open PR #12, not merged yet, adds @ibxlab/mandate/assay, so an agent under a mandate only pays inference hosts that verifiers it trusts grade pass. The check is one view call to gradeOf, it fails closed, and it adds no dependencies (10 tests).
Proof: aliveevie/mandate#12
Context that carries its own receipt
Mida keeps what one agent learned, encrypted under the user's keys, so the next agent the user approves can pick it up. A Mida record now carries the Assay receipt of the call that produced it, with its salt inside the encrypted body. Before using the context, the next agent runs checkRecord: the host must be pinned, the receipt anchored, and the salt must open both commits. The Mida team built their side and merged it into this repo. Their test run saved a receipt with one agent, read it with a second, then revoked the reader. They also found a gap in our offline mode, now fixed.
Proof: PR #6 · examples/mida-context/ · sdk/test/record.test.ts
A Kimi host, and 16 Kimi hosts graded
Host agent 10316 serves Kimi K2.6 on mainnet from Moonshot's own endpoint, and every answer gets a receipt. We graded all 17 OpenRouter endpoints for Kimi K2.6, plus our host, against Moonshot's endpoint: 16 graded hosts and ours passed 32/32 tool-calling checks, whatever precision they claim (int4, fp4, fp8, bf16 or none). Three of them ignored the token limit set in the request. One rate-limited every request, so it got no grade.
Proof: 17 grades onchain · docs/evidence/grades_20261008T033914Z.json
Per-app keys that never hold MON
A per-app address delegates to AssayAccount with EIP-7702, and the host's relayer pays the gas for its co-sign and for its ERC-8004 feedback. The relayer only pays for feedback about its own host that cites a receipt the sender co-signed, so it can't be drained for anything else. A fresh address with zero MON co-signed and filed feedback on testnet, and still had zero afterwards.
Proof: contracts/src/AssayAccount.sol · a fork test against the real ReputationRegistry · host/src/sponsor.ts
Live: a host paid per verified receipt
Kanmani runs an escrow on Monad mainnet that settles metered jobs in USDC. On 9 Oct they bought 5 responses from host 10278 and published the Merkle root of the 5 receipt hashes in advance. We delivered that root to their escrow. Both sides checked each receipt against our anchored batches, and Kanmani settled 5 units: 0.05 USDC to the host's owner. On 12 Oct a second job (5 responses at max_tokens 1,500) settled the same way, so 10 receipts and 0.10 USDC so far.
Proof: issue #4 · job 1 deliver 0x9f9055ff… · job 1 settle 0x69aef08c… · job 2 settle 0xd74d97dc…
The threat model maps every attack to the test that blocks it: docs.
| Property | Proof (Foundry) |
|---|---|
| A host can't anchor with a key that isn't its own, or replay a batch | test_anchor_wrongKey_reverts · test_anchor_replay_reverts |
| A signature can't move to another chain or deployment, and the count can't be changed | test_anchor_otherDeployment_reverts · test_anchor_countTampered_reverts |
| One host can't front-run another host's root | test_anchor_otherHostSameRoot_doesNotBlock |
| A receipt only verifies under the host that anchored it | test_verifyReceipt_otherHostsAnchor_false |
| A stranger co-signing first can't block or impersonate the requester | test_cosign_otherKeyFirst_doesNotBlock · test_cosignK_otherSignerFirst_doesNotBlock |
| A passkey co-sign needs user verification and low-s | test_cosign_missingUV_reverts · test_cosign_highS_reverts |
| Key rotation keeps old anchors valid, and grades don't follow the key | test_setHostKey_rotation_keepsOldAnchors · test_gradeOf_otherHostKeyIsSeparate |
| Stale grades and sold identities can't post | test_post_staleGrade_reverts · test_post_afterIdentityTransferred_reverts |
| An attestor only accepts reports from its forwarder and workflow, and v2 also only from transactions our relayer sent, written once per grade. (v1 trusted the CRE simulator's public ids, so anyone could write to it; it's retired.) | test_onReport_withRelayer_onlyRelayersTransactionsLand · test_onReport_secondReportSameGrade_reverts_andKeepsTheFirst · test_onReport_nonForwarder_reverts |
| The P256 precompile is live, never the 250k-gas fallback | test_precompile_knownVector_returnsOne · test_valid_usesPrecompile_gasBound |
| A real browser passkey co-sign from mainnet verifies, and changing any byte of it fails | MainnetReplayTest (replays the real anchor and co-sign transactions) |
| Only a host's own signature anchors, never twice, and a receipt verifies only under a host that anchored it | ReceiptAnchorInvariantTest (3 invariants, random call sequences) |
| A sponsored call only runs if the per-app key signed it, once, on this chain, before its deadline |
| Package | Tests |
|---|---|
| Contracts (Foundry) | 123, plus fork tests against the real ERC-8004 registries |
SDK @assay/receipts | 156, including cross-implementation checks of MonadGuard's receipts |
| Host | 74, plus a 16/16 end-to-end run on a local chain in CI |
| Web app | 96 |
| Grader (Python) | 47 |
| Envio indexer | 24, plus the HyperSync stats script |
| Chainlink CRE workflow | 31 |
| Total | 551, across 6 CI workflows |
TypeScript and Solidity check each other: the SDK generates the signatures and Merkle proofs that the Foundry tests verify.
| Path | Contents |
|---|---|
contracts/ | Foundry: ReceiptAnchor, VerifierRegistry, CreAttestor, tests, fork tests, deploy scripts |
sdk/ | @assay/receipts: receipts, salted commits, ES256 signing, Merkle batches, verifyReceipt, passkeys, wrap(fetch) with the grade gate, gradeOf |
host/ | @assay/host: OpenAI-compatible proxy (Hono) that signs, batches and anchors, relays co-signs, serves /v1/grade |
web/ | Landing page plus app: verify, receipt pages, ask and co-sign, grades, Mera vault (Vite, plain TypeScript) |
indexer/ | Envio HyperIndex: anchors, keys, co-signs, grades, drift, leaderboards, ERC-8004 feedback |
cre/ | Chainlink CRE grade-recheck workflow and its simulations |
harness/ | The grader (Python, stdlib only): probes hosts against the lab's API, exports grades and evidence |
report/ | Who's actually serving your model? Report v0 |
| · |
You need Node 22+, pnpm (corepack enable) and Foundry 1.7+.
git clone --recurse-submodules https://github.com/trudransh/Assay.git && cd Assay && pnpm install
cd contracts && forge test -vv && cd .. # contracts
pnpm -r test # sdk, host, web
pnpm --filter @assay/host dev # host on :8787 (copy .env.example to .env first)
pnpm --filter web dev # app on :5173
Try the grader. The dry run needs no key and prints the cost first:
python3 harness/assay_probe.py --model z-ai/glm-5.3 --dry-run
After changing hashing, signing or Merkle code, run pnpm --filter @assay/receipts gen:vectors, then forge test, so both sides stay in step. Fork tests: forge test --match-path "test/fork/*" --fork-url monad_testnet -vv.
Welcome · Quickstart · Core concepts · Receipts · Passkey co-signatures · Verifiers and grades · Privacy · SDK · Threat model · Roadmap
Everything here was written during Monad Metropolis. The grader in harness/ and report v0 were written in the last week of September, just before the first commit. Everything else, the contracts, SDK, host, indexer, CRE workflow and web app, was built from 30 September onward, and the commit history shows it day by day.
Built on OpenZeppelin Contracts 5.7.0 (P256, WebAuthn, MerkleProof), Foundry, viem, jose, canonicalize (RFC 8785), @openzeppelin/merkle-tree, Hono, Envio HyperIndex, Chainlink CRE and Mera. The ERC-8004 registries are the official deployments from erc-8004/erc-8004-contracts. Third-party measurements are credited in the report.
Assay · MIT License · built for Monad Metropolis, Track 4
host/src/sponsor.ts |
| ⚠️ | The tool-calling checks are easy: every host we graded passed. The token-cap test is the first one that separates hosts | harness/ |
| ❌ | Which weights ran. A receipt proves who served which bytes and what they claimed, not the model behind them | roadmap |
| ✅ | The SDK is on npm as assay-receipts (0.2.0) | sdk/ |
AssayAccountTest (12 tests, including a fuzz test) |
docs/| Deployments, evidence, threat model; the GitBook site |