Project Siren + ENS: how should an ENS identity link to a verifiable benchmark certificate?

Hi ENS community,

I would like to open a technical discussion around project Siren and how it should align with ENS-native identity and discovery patterns.

Siren is a public verification and scoring layer for ENS-named agents, projects, companies, teams, and on-chain entities.

The basic idea is simple:

More agents and projects will use ENS names as their public identity. But an ENS name alone does not tell an investor, launch platform, partner, or user whether that entity is active, credible, or backed by real public evidence.

Project Siren tries to fill that gap.

A user enters an ENS name, and Siren reads public evidence around that subject, such as ENS records, GitHub activity, on-chain activity, and verified contract data. It then produces a transparent benchmark score, tier, risk signal, and report.

The result can also be represented as an EAS attestation / benchmark certificate with a payload similar to:

{
  "subject": "0x...",
  "ensNamehash": "0x...",
  "score": 82,
  "tier": "A",
  "computedAt": 1770000000,
  "reportHash": "0x...",
  "reportUri": "https://..."
}

In the current implementation, project Siren already has an ENS-specific subject manifest namespace:

agent-bench:bench_manifest
agent-bench:owner
agent-bench:schema

This manifest can declare the public sources that should be evaluated for a subject.

For subjects without an explicit manifest, Siren also has a public-read fallback. It reads common ENS records such as:

com.github
description
url
avatar
com.twitter
com.linkedin

and also looks for contract/source hints such as:

org.sourcify
sourcify
Sourcify
contract
verified-contract
agent-bench:contract
agent-bench:contracts

This already works technically, but it raises a bigger design question:

What should be the ENS-native way to link an ENS name to a verifiable benchmark certificate?

My current mental model is:

ENS name = public identity
ENS records = discovery surface
Project Siren = evidence + scoring layer
EAS attestation = portable benchmark certificate
reportHash/reportUri = reproducible evidence object

What I would like to understand from the ENS developer community:

  1. Should an ENS name store only a pointer to the latest Siren/EAS attestation, or should selected metadata such as score, tier, and reportUri also be exposed as text records?

  2. Would it make sense to use an ENSIP-26-compatible pattern for agents, for example agent-context and agent-endpoint[web], rather than creating a separate Siren-only discovery model?

  3. If project-specific records are useful, would a namespace like this be acceptable?

siren:attestation_uid
siren:attestation_network
siren:report_uri
siren:report_hash
siren:score
siren:tier
siren:updated_at
  1. Or would it be better to keep ENS records minimal and store only something like:
siren:latest = eip155:11155111/eas:0x...

with all score details living inside the EAS attestation and report?

  1. Should the canonical attestation live on the same chain as the subject, on mainnet, on Base/Optimism, or should the network be explicitly encoded in the ENS record?

  2. How should updates be handled? If a Siren score changes over time, should ENS point to the latest attestation, an attestation history, or only to a stable report endpoint?

  3. Is it dangerous or misleading to expose score and tier directly in ENS records, since they may become stale while the underlying evidence changes?

  4. Would ENS clients prefer flat records, a single JSON manifest, or a hybrid where ENS stores a small pointer and the full schema/report lives offchain or in EAS?

  5. Is there already a preferred ENS pattern for linking names to attestations, reputation objects, verification reports, or credentials?

  6. From a UX perspective, could a future flow make sense where a user enters a Siren attestation UID, and a UI pre-fills suggested ENS records for the ENS name owner to review and sign?

To be clear, I am not suggesting that project Siren should automatically write to someone else’s ENS records. The ENS name owner should remain fully in control.

The question is about the cleanest representation:

How should an ENS identity discover, reference, and expose a verifiable benchmark certificate without duplicating too much mutable data inside ENS records?

I would appreciate feedback on whether this direction makes sense, which records should be used, and what the cleanest ENS-native integration path would be.

1 Like

I would recommend you take a look at our new metadata standard (ENSIP-64). It allows you to attach a json schema to an ENS name which makes the text records discoverable and machine-readable, even if the client doesn’t know what standard naming conventions you are following.

The obvious starting use case is that you could outline all of the data you want to publish in a schema file, and anyone who looks at your ENS name will have all the details to consume it: if they are already familiar with the data structures you are using they can use ENSIP-64 functionality for discovery and parsing, but also anyone who doesn’t know the details of what you are working on can use your published schema file to understand what they are looking at and find links to resources for more information, which improves discoverability greatly.

Here’s an example of how to use our AI agent schema to publish rich metadata for an agent: Use Case: AI Agents on ENS Β· Issue #46 Β· 0xLighthouse/ens-metadata Β· GitHub What you might find interesting is the parts where it talks about what records to put on-chain as independent records versus aggregating off-chain.

We’d be happy to help you create and publish a schema that includes the data sets you’ve described, if you would like to play around with this new standard! You should also check out our web interface: ensmetadata.app and the docs (docs.ensmetadata.app)

1 Like

ERC-8121 allows for a pointer, or β€œHook,” to any external contract function, with a fully specified function call, contract, and chain, while also requiring that ERC-3668 CCIP-Read be β€œturned on,” allowing for offchain data resolution.

For an ENS profile, it allows for the inclusion of attestations to the metadata, where the attestation is not mutable by the profile owner, allowing for any kind of credential or endorsement to be included in the profile.

https://eips.ethereum.org/EIPS/eip-8121

2 Likes

Would this work for ens.app pointer?

How would ERC-8121 pointing to an off chain resource be better than a regular URL pointing to the same off-chain resource?

1 Like

@premium because that hook allows for the most current human readability while at the byte level confirm how trustworthy an off chain contract is during interoperation at the 4-byte level? To cite:

functionSelector: (OPTIONAL) The 4-byte selector of the function to call. When provided, this acts as a checksum to verify the functionSignature. If omitted, the hook structure starts with functionSignature as the first parameter. Clients can always derive the selector from functionSignature.

A regular url redirect does not handle off chain interoperation hooking into smart contracts that ERC8121 can handle at the byte level.


The ERC-8121 hook pattern solves exactly the problem this thread is circling: how do you link an ENS record to a verifiable off-chain contract interaction without duplicating mutable data inside ENS?

The answer is: you don’t store the score or tier in ENS at all. You store the functionSelector + functionSignature as the ENS pointer. The 4-byte selector is the checksum. Any client reading that record can derive the selector from the signature and know whether the off-chain Siren endpoint still speaks the same interface β€” at the byte level β€” before trusting the attestation it returns.

This is why siren:latest = eip155:11155111/eas:0x… alone is insufficient. It’s a pointer with no integrity check. ERC-8121 hooks turn it into a pointer with a verifiable contract interface fingerprint.

For ens.app specifically: I’ve implemented this pattern as a BNS v2 Pointer NFT on Stacks, where the zonefile metadata carries the canonical ENS redirect and the Clarity contract enforces one-time initialization with ownership proof. The same architecture β€” pointer + hook checksum β€” applies cleanly to the Siren attestation flow on ENS.

Because ERC-8121 requires that ERC-3668 CCIP-Read is β€œturned on,” it enables reading offchain records and verifying them onchain. This can be a powerful pattern, particularly when using ZK proofs, where large amounts of computation can be verified onchain.

In this particular use case, what smart contract function would it be pointing to? Wouldn’t Siren have to deploy their own smart contract that includes the on-chain verification functionality, as well as the off-chain resource? (I guess this is more a question for Siren, unless you have some ideas!)

@jkm.eth Great question β€” and yes, this lands on us. Here’s the
concrete answer after working through the ERC-8121 spec carefully.

═══════════════════════════════════════════════════════════
NOTE: Project rebrand (relevant to records named below)
═══════════════════════════════════════════════════════════
Siren is the hackathon name from ETHPrague 2026. Production
release is branded VerAL β€” Verification Authority Layer for
Ethereum. Same project, same ENS-anchored architecture, same
team. ENS namespace migrates from siren.* to veral.* with
backward compatibility through Term 1. I’ll use Veral in the
technical examples below since that’s the production identity.

═══════════════════════════════════════════════════════════

The pointer on Veral’s side would target the EAS contract’s
getAttestation function (v1.0), with a thin Veral verifier contract
as an upgrade path (v1.5+). Both paths satisfy ERC-8121’s selector
checksum and CCIP-Read enablement requirements.

═══════════════════════════════════════════════════════════
OPTION A β€” EAS-native, no custom contract (v1.0 ship target)
═══════════════════════════════════════════════════════════

The ENS record veral.cert (per-tier records below) points to the EAS
mainnet contract directly:

contract: 0xA1207F3BBa224E2c9c3c6D5aF63D0eb1582Ce587
functionSignature: β€œgetAttestation(bytes32)”
functionSelector: 0xa3112a64 // bytes4(keccak256(signature))
parameter: <Veral cert UID for the subject + tier>

The selector here is the actual derived value (verified via
cast sig), satisfying ERC-8121’s checksum requirement β€”
bytes4(keccak256("getAttestation(bytes32)")) produces 0xa3112a64,
clients reject if the embedded selector doesn’t match.

EAS getAttestation returns the full Attestation struct (data,
attester, time, expirationTime, revocationTime, refUID, schema,
recipient), which embeds our Veral schema payload: tier, score,
validUntil, signer, evidenceBundleHash, scoreFormulaVersion,
optional aiProvenanceHash + forensicHash, and previousUID for
renewal chains.

ERC-8121 mandates clients enable CCIP-Read capability before
resolving. The EAS contract itself doesn’t trigger an off-chain
fetch (data comes from on-chain SLOAD), but the client’s CCIP-Read
runtime is enabled β€” fully spec-compliant. This is the simplest
path to a working ENS-anchored verifiable cert with zero new
contracts from us.

═══════════════════════════════════════════════════════════
OPTION B β€” Veral verifier contract + CCIP-Read (v1.5+ path)
═══════════════════════════════════════════════════════════

A thin read-only Solidity contract deployed via CREATE2 (same
address per chain via deterministic factory pattern):

contract VeralVerifier {
function verifyForSubject(bytes32 ensNamehash, uint8 tier)
external view
returns (
bytes32 currentUID,
uint16 score,
uint64 validUntil,
bool isExpired,
bytes32 evidenceBundleHash
);

  function listActiveTiers(bytes32 ensNamehash)
      external view
      returns (bytes32[] memory uids, uint8[] memory tiers);

}

Critical design correction from my own thinking: storage stays in
ENS, not in the verifier contract. The verifier reads ENS text
records veral.cert.public / veral.cert.anchored /
veral.cert.sealed (UIDs published by the subject via setText on
issuance), then forwards to EAS for the attestation data. No
Veral-side contract storage = no upgrade migration risk, no Veral
single point of write, ENS-native subject control over their own
records.

This contract pairs with CCIP-Read for cross-chain cert discovery:
the gateway returns signed payloads (ECDSA today; in v2.0
potentially ZK-proven if score formula computation is moved into
a verifiable circuit), validated on-chain by the verifier.

ERC-8121 pointer:

functionSignature: β€œverifyForSubject(bytes32,uint8)”
functionSelector: <derived via bytes4(keccak256(…))>
parameter: ensNamehash + requested tier

═══════════════════════════════════════════════════════════
ON THE MULTI-TIER QUESTION
═══════════════════════════════════════════════════════════

A subject may hold multiple active Veral certs simultaneously
(e.g. Public + Anchored, or all three tiers). To handle this
cleanly:

ENS text records, one per tier:
veral.cert.public β†’ EAS UID for active Public cert
veral.cert.anchored β†’ EAS UID for active Anchored cert
veral.cert.sealed β†’ EAS UID for active Sealed cert
veral.cert β†’ pointer to the highest active tier
(convenience for clients wanting β€œbest”)

Each record updated via setText on each issuance / renewal β€” one
transaction per tier per renewal, gas amortized across tier
independence (no cross-tier interference, subject controls timing).
ERC-8121 hook can target any of the four β€” wallet shows tier-
appropriate cert, explorer surfaces all, governance forums quote
the highest.

═══════════════════════════════════════════════════════════
ON ZK PROOFS AND OPERATOR TRUST
═══════════════════════════════════════════════════════════

To soften an earlier statement of my own: ZK proofs (when we ship
them in v2.0) reduce the operator’s trust scope, but don’t eliminate
it. The math:

ZK proves: β€œgiven evidence bundle hash X, score formula produces Y”
(arithmetic correctness β€” verifiable in circuit)

Operator
still attests: β€œthe evidence bundle X was honestly fetched from
Sourcify/GitHub/etc β€” these are the real values”
(data authenticity β€” separate problem, requires
TLSNotary-class proofs or trusted source signing)

So v2.0 with ZK proofs collapses the trust surface from β€œmath +
data” to just β€œdata” β€” significant, not full elimination.

═══════════════════════════════════════════════════════════
ON THE BROADER PRIMITIVE
═══════════════════════════════════════════════════════════

To answer the implicit framing in @Premm.eth’s earlier point β€” a
plain URL redirect doesn’t give clients interface stability at the
byte level, and doesn’t compose into the EAS / CCIP-Read / ZK
verification stack the ecosystem is converging on. ERC-8121’s
contribution is making the pointer itself a typed, checksummed
interface fingerprint with mandatory CCIP-Read enablement. We agree
it’s the right primitive for verifiable attestation pointers.

═══════════════════════════════════════════════════════════
OPEN QUESTIONS (for the ENS DAO + ERC-8121 reviewers)
═══════════════════════════════════════════════════════════

  1. For multi-tier subjects with parallel active certs, is the
    veral.cert.{tier} per-record pattern preferable to a single
    record encoding multiple UIDs (gas-cheaper but less ERC-8121-
    composable)?

  2. For ERC-8121 multi-chain readers, deterministic same-address
    deployment via CREATE2 vs chain-specific addresses in the pointer
    β€” does the spec favor one, or is this issuer choice?

  3. Is there appetite in the ENS community for a standard verifier
    interface that issuers (Veral, and potentially others β€”
    Verax-class attestation services, audit firms, identity
    providers β€” if they choose to align) could implement, giving
    wallets a single integration point for attestation resolution?

The ZK-proof + CCIP-Read direction @Premm.eth referenced is exactly
where we see this going in v2.0, once the off-chain score engine
graduates to a verifiable circuit.

2 Likes