Messaging & Note-Privacy Capabilities
ChainRender renders on-chain messages and private-payment discovery honestly, and declares the sends — it never
becomes a messaging protocol, an inbox, a relay, or an indexer, and it never custodies a key. Everything here is graded
by the same rule as the rest of the system: a re-computable view is Grade A; an event-log feed or a client-side
render is ≤ C and labelled; a send is a declared action. (Full strategy: doc 157.)
The one rule that decides the grade
| Where the work happens | Example | Treatment |
|---|---|---|
Re-computable eth_call view |
ERC-1271 validity, ERC-6538 lookup, shielded-pool invariants | Grade A |
On-chain data via eth_getLogs / indexer |
ERC-3722 Poster feed, ERC-5564 announcement scan | ≤ C, labelled |
| Client-side / RPC crypto (never on-chain) | EIP-712 signing, ERC-5630 encrypt, stealth derivation | declared / local |
| A state change | ERC-5564 announce, ERC-3722 post |
declared action |
An event-log feed is not Grade A: logs are verifiable but read via eth_getLogs, not a view a component can
re-run — so Poster feeds and stealth scans render at ≤ C with a labelled off-chain edge (the same posture as EFP
follower counts).
Public messaging
- ERC-1271 signature validity (
sig-1271, Grade A) — "is this message hash validly signed by contract account X?" A pureviewagainst the account's own logic. Validity only — the meaning of the message is rendered client-side (seemsg-712), never asserted here. - Render what you sign (
msg-712, client-side, ≤ C) — an honest render of the EIP-712 / EIP-191 message you are about to sign: every field named and typed, and fail-closed on anything opaque ("this field is raw bytes we can't interpret — do not sign blind"), with an A-hint only when the message is fully typed and bound to averifyingContract. Anti-phishing infrastructure, framed as "marketing ≤ code" — it never says "safe to sign." - ERC-3722 Poster feed (
poster-feed, ≤ C) — public posts. Content lives only inNewPostevent logs (no state), so it's an indexer read, labelled off-chain. Declaring apost()is a user action.
Private messaging & payments
- ERC-6538 stealth discovery (
stealth-meta, Grade A) — "is this address reachable via stealth payments, and what is its published stealth meta-address?" This discovery read is the only on-chain (Grade A) part of a private payment. The ERC-5564announcesend is a declared action; scanning announcements (stealth-scan, ≤ C) is an off-chain log read; deriving which announcements are yours uses your viewing key, client-side. ChainRender never holds a key or derives your address server-side. - ERC-5630 encryption is client/RPC-side by construction (
eth_getEncryptionPublicKey/ ECIES) — rendered + declared, never a chain read, never custodied.
Shielded pools / note privacy (Aztec / zk.money-style)
Render the privacy boundary honestly — the publicly-provable invariants, revealing nothing about ownership:
shielded-root(Grade A) — the pool's current Merkle root.shielded-set(Grade A) — the anonymity-set size, i.e. how private the pool actually is right now. A small set is weak privacy — the card grades it WEAK / moderate / healthy and says so, instead of hiding a thin set.shielded-nullifier(Grade A) — is a nullifier spent (double-spend / already-claimed) without revealing identity.
The decrypted balance is a client-side, viewing-key-gated enhancement (≤ C, local) that fails closed to this
public floor. Shield / unshield / transfer are declared actions whose privacy leaks are labelled, never hidden:
deposit reveals the amount + your L1 address; the internal transfer is private; withdrawing to a reused address re-links
you — use a fresh one. This reuses the same commitment+nullifier DNA already shipped (Groth16 credentials + the
ownerless NullifierRegistry).
Honest boundaries
- No key custody. Never a messaging protocol, inbox, relay, or indexer.
- No plaintext private content on-chain. Off-chain delivery (hubs, CCIP-Read, ciphertext stores) is ≤ C and labelled.
- A rendered signable message is a render, not an endorsement — it states what the message is and where it's opaque.
- A weak anonymity set is rendered as weak. Marketing ≤ code.
For developers
Kinds are discoverable via RESOLVER_KINDS / vocabulary(); encode args with the helpers in @chainrender/client
(chainc/messaging.ts): encodeSig1271Args, encodeStealthMetaArgs, encodeShieldedArgs, plus the client-side
renderTyped712, decodePrivacyLeaks, and posterFeedFilter. On-chain resolvers:
Sig1271Resolver, StealthMetaResolver, ShieldedPoolViewResolver (caller-supplied addresses; fail-closed; ownerless).