Validator Metadata Registry

What this MRC is proposing

A draft MRC for a permissionless on-chain registry of validator metadata. Each validator’s authority address — as already known to the staking precompile — can publish a record containing their name, website, description, logo, socials, and a forward-compatible JSON extension blob, keyed to the validatorId.

The problem it solves

The staking precompile knows what consensus needs — validator IDs, authority addresses, stake, commission — but nothing humans can read. Today every wallet, explorer, dashboard, and delegation tool solves this independently: maintain your own metadata.json file, scrape socials, ask validators directly. The result is fragmented naming across the ecosystem and a quiet concentration of “who gets to label validator N” in whoever happens to be curating the list a user is looking at.

A registry contract where validators publish their own metadata is the obvious fix. No protocol change needed — it’s a pure application-layer addition. The value of the standard is that wallets, explorers, governance UIs, and indexers can all read from a single shape.

The interface

The MRC defines IValidatorMetadata:

- A Metadata struct with name, website, description, logo, socials, additionalInfo.

- setMetadata (write the whole record) and updateMetadataField (update one field).

- A MetadataUpdated event on every write.

- Read methods for the stored record plus convenience getters.

socials and additionalInfo are stored as JSON-by-convention strings: the registry doesn’t parse or validate them, so writers and consumers carry the schema. socials is suggested as a JSON object keyed by lowercase platform identifier ("x", "telegram", …) so the spec doesn’t bake in today’s platforms; additionalInfo is open-schema for downstream MRCs to layer structured extensions on top.

A few design choices worth highlighting

Authority address as the baseline writer, not the sole writer: The validator’s authority address must be accepted; implementations may extend the writer set — delegated keys, multisigs, governance contracts — under their own rules. Forcing teams to touch the staking key just to update a logo URL is the kind of friction that pushes people back to off-chain curation, which is the worst of both worlds.

No canonical implementation, no curator: The MRC defines the interface; integrators and validators pick which conformant deployment(s) to use. The authors will deploy a reference implementation for their own use, but the MRC does not anoint it, and neither Monad Foundation nor any affiliate acts as a curator of validator metadata.

JSON, not custom encodings: Off-chain consumers in this space already speak JSON. Pinning a serialized struct or a binary format would force everyone through extra plumbing for marginal gain, and would lock the schema in ways that prevent forward-compatible extensions.

Immutable contract, no upgrade path: Future MRCs that change the storage layout or interface deploy at new addresses. The standard does not promise a stable address over time; integrators track which deployments they consider current themselves.

Read the full draft

Comments, critiques, and integration questions welcome in this thread.

7 Likes

Supportive — I sit on both sides of this: a validator (testnet id 267) currently published via the off-chain validator-info repo, and the operator of MonadPulse, a third-party indexer that reads names from it today. A single on-chain shape I write myself removes the “who labels validator N” fragmentation directly.

One addition worth considering for additionalInfo: a conventional key for self-declared infrastructure (hosting provider / ASN / region). Today infra concentration is only visible by scraping gossip and mapping IPs to ASNs by hand; a validator-declared field would give explorers and delegation tools a first-class place to surface provider diversity. Open-schema in additionalInfo keeps it optional and forward-compatible.

Happy to integrate the reference deployment into MonadPulse once it’s live.

1 Like

We support this direction. From a validator operator perspective, this solves a very real problem: validator identity is currently fragmented across explorers, wallets, dashboards, and privately maintained lists. That creates inconsistent names/logos, stale links, and unnecessary dependence on whoever curates a given frontend.

Having validator-controlled metadata anchored to the same authority model used by staking feels like the right baseline. It keeps the registry permissionless, makes the source of the update auditable, and gives integrators a simple common shape to read from.

A few points I’d like to highlight:

First, I strongly agree that the authority address should be the required baseline writer, but not necessarily the only writer. In practice, teams should not have to touch their core staking authority key just to update a logo, website, or social link. Delegated metadata managers, multisigs, or governance-controlled update flows are important for real validator operations.

Second, the JSON fields for socials and additionalInfo are a pragmatic choice. Wallets, explorers, and indexers already know how to consume JSON, and keeping those fields open-ended makes the standard future-proof without forcing a new registry every time the ecosystem wants to add a new metadata field.

The one area I think needs careful coordination is deployment discovery. If the MRC intentionally does not define a canonical contract address, that is good from a neutrality point of view, but integrators still need a reliable way to know which deployment(s) the ecosystem currently treats as active. Otherwise we may partially recreate the same fragmentation problem at the registry-address level. This does not need to be a Foundation-curated list, but some lightweight discovery convention or well-known registry-of-registries pattern would probably help wallets and explorers converge.

I would also encourage clear consumer-side guidance: all metadata should be treated as self-attested and untrusted. UIs should sanitize strings, validate URL schemes, avoid blindly loading arbitrary remote images, and show validatorId / authority address somewhere accessible so copied names or logos do not become a phishing vector.

Overall, this is a good application-layer standard. It does not require protocol changes, it respects validator self-sovereignty, and it gives wallets/explorers/indexers a shared interface instead of pushing everyone into private metadata files. POSTHUMAN would be happy to support this kind of standard.

1 Like

Supportive, and this sits close to what we work on. We run ProofLine, a Japan testnet full-node, and publish a geo and ASN concentration map of the active set. We build it by scraping peer endpoints from gossip, mapping IPs to ASNs, and aggregating by provider, so the “who labels validator N” fragmentation shows up on the infrastructure side too, not just naming.

That points to one field worth considering for additionalInfo: a conventional key for self-declared infrastructure (hosting provider / ASN / region). It is useful on its own, and its value grows when it can be cross-checked against what the network actually observes. We already produce that observed side (provider and ASN inferred from live peer endpoints), so a declared field would let explorers and delegation tools surface drift between what an operator states and what is measured: stale entries, accidental mislabels, or a node that quietly moved hosts. That makes the field more self-correcting rather than another value nobody audits.

On our end we would read the registry as a consumer. Our dashboard currently infers operator identity and provider externally, and a canonical on-chain record to join against would replace a good chunk of that guesswork. Keeping it open-schema in additionalInfo keeps the convention optional and forward-compatible.

If there is appetite for the infra-field convention, we can bring our observed-side data to help define it.

1 Like

Great idea. I’ve spent a lot of time in different blockchain explorers lately and this was a problem everywhere. More than 50% of validators didn’t even have a description or name.

At the same time, some profiles were filled out really well, which reflects the exact issue you’re talking about.

The only thing that concerns me is that pfps will stay offchain. Let’s make our own monad validator punks.

@ColinkaMalinka the declared-vs-observed cross-check is the right framing — a self-declared field only stays honest if something measures drift against it, and that’s what makes it worth standardizing instead of being another unaudited string. I produce the same observed side in MonadPulse (provider / ASN inferred from live peer endpoints), so happy to help define the convention alongside ProofLine.

A concrete minimal shape for the additionalInfo key, all fields optional:

“infrastructure”: { “provider”: “ovh”, “asn”: 16276, “region”: “ap-southeast” }

That’s enough for explorers to surface provider diversity and for either of our dashboards to flag declared-vs-observed mismatches, while staying open-schema. If the authors would rather keep additionalInfo fully freeform and layer this in a follow-on MRC, that works equally well.

If multiple registries contain different metadata for the same validator, how should integrators resolve conflicts? Is the expectation that the ecosystem converges on a small number of trusted deployments over time?

From the integrator seat (MonadPulse): I’d anchor trust on the authority address from the staking precompile, not on any single registry — “who wrote it” matters more than “which registry,” which turns most conflicts into a recency question rather than a trust one. For objective fields like the infrastructure one above, the observed gossip data is a natural tiebreaker: the record matching what the network actually shows wins.

The convergence/discovery half — which deployments count as current — is the real open one, and that’s for the authors. +1 that some lightweight discovery convention would stop this recreating the fragmentation at the registry-address level.

We agree and fully support this direction. A validator-controlled metadata registry would reduce fragmentation across explorers, wallets, and dashboards, while giving operators a simple and transparent way to keep their information accurate and up to date.

+1 to @ShadowOfTime1 on anchoring trust on the authority address rather than any single registry, that turns most conflicts into a recency question.

for the objective fields (infrastructure especially), observed network data is a clean deterministic tiebreaker: when records disagree, the one matching what the network actually shows wins. we already produce that observed side for the full active set (asn/provider/region inferred from live peer endpoints, 200/200 in our current snapshot), so it can serve as the reference for resolving those conflicts, not just for flagging drift.

on discovery, the spec deliberately leaves deployment choice to integrators with no canonical curator, which is the right call. a lightweight, non-curated discovery convention (the registry-of-registries idea raised above) would stop fragmentation reappearing at the registry-address level without recreating a curator. authority-address trust plus observed-as-tiebreaker for objective fields covers most of the practical cases meanwhile.

Hi Đorđe,

I built a reference implementation of MRC-13 to see how the proposal holds up as running code, and wanted to share it in case it’s useful for the discussion.

It follows the interface from your draft: the Metadata struct (name/website/description/logo/socials/additionalInfo), setMetadata / updateMetadataField, the MetadataUpdated event, and the getters. Writes are authorized against the validator’s authority address from the staking precompile, as the draft specifies, and the authority can delegate write access to another key so routine updates don’t need the staking key.

Around the contract there’s a small TypeScript/viem resolver, a sanitizer for the phishing concern that came up (strips zero-width and bidi characters, blocks non-http(s) URLs, flags invalid JSON), a migration tool that turns the existing validator-info entries into setMetadata calldata, and an events indexer that rebuilds a directory from chain.

I deployed it to testnet and wrote my own validator’s record (id 267) with it, so there’s a live example and not just code:

Registry on testnet: 0x3f084CAF88F8894f6c83cf40b9cA7e792D9F221B

I took positions on the three open questions from the thread (discovery via authority-address trust rather than a canonical registry address, conflict resolution following from that, and consumer-side sanitization), but that’s just my reading. This is your proposal, so I’d rather match wherever the draft lands. Happy to change the interface or anything else, and corrections are welcome.

Roman

Nice to see this as running code, the migration tool and the events indexer especially.

One layer worth adding on top: the indexer rebuilds the directory from what operators declare, but for objective fields like infrastructure (provider / asn / region) nothing checks that the declared value matches reality. That is the piece ProofLine already produces. We derive provider/asn/region for the full active set from the live gossip endpoints, so the observed map can sit next to the indexer as the tiebreaker this thread landed on earlier: when a declared field and the measured one disagree, the record matching the network wins, so stale or mislabeled entries surface instead of resolving silently.

Happy to expose that observed side in whatever shape the resolver wants to read. Keeps the contract as-is and the standard clean, with the declared-vs-observed cross-check as an optional consumer-side layer rather than anything on-chain.

Agreed, and I’d keep it exactly where you put it: consumer-side, contract unchanged. The registry stays the declared record, and an observed map is a separate input to cross-check against.

I run the observed side too (my validator plus a non-validating mainnet node, and I’ve been collecting peers.toml from operators in a few regions for cross-confirmation), so meeting in the middle is easy. The shape that would work: the resolver takes an optional observed source returning {provider, asn, region, confidence, source} per validator id, and for those objective fields it shows a status next to the value, verified when declared and observed agree, disputed when they don’t, unverified when there’s no measurement. Additive and fully off-chain.

Several independent vantages beat any single one, so ProofLine exposing its observed side in that shape would be great, mine can sit beside it and cross-confirm rather than trusting one map. If there’s appetite for it in scope, I’m happy to sketch the interface so there’s something concrete to react to.

One caution: surfacing a mismatch helps fix stale entries, but a per-operator “wrong” list reads differently, so I’d lean toward showing status and letting operators correct their own records rather than a leaderboard of mislabels.

Rather than keep it abstract I dropped a concrete version in the repo so it’s runnable: an interface sketch plus a live observed feed in that shape (issue #1). It follows what you laid out, source-labelled, and keys observations by validatorId so active-set rotation doesn’t drop anyone. Happy to fold your shape in and match wherever the draft lands.

We are fully supports this MIP.
We see the current fragmentation across explorers and dashboards as a real issue. An on-chain registry controlled by the same authority address used for staking is the cleanest way to fix it. Validators should be able to manage their own name, logo, and links without depending on third-party lists.
We like that the design keeps the authority address as the baseline while still allowing teams to delegate metadata updates through multisigs or operators. That matches how most validators actually work in practice. The JSON fields for socials and additionalInfo also make sense for keeping the standard flexible over time.
Once a reference deployment is live, OnNode plans to register our metadata through it and read from the registry in our own tooling. This is a solid step toward a more consistent and self-sovereign validator ecosystem.

Thanks all, and thanks @mijovic for the proposal.

A reference deployment is already live on Monad testnet (chainId 10143) at 0x3f084CAF88F8894f6c83cf40b9cA7e792D9F221B, with my own validator (id 267) registered through it as a worked example. @OnNode, you can register against it and read from it today; I’d be glad for feedback from real use.

@ColinkaMalinka, the observed cross-check in issue #1 is exactly the right shape: consumer-side, off-chain, registry untouched, per-validator status rather than a mislabel list, keyed by validatorId so rotation doesn’t drop anyone. Happy to take the PR. I’ll add a second observed source from my own vantage so the two cross-confirm rather than relying on one map.

Interface naming and thresholds are open, and I’ll track whatever the draft settles on.

1 Like

I also worked on a reference implementation of MRC-13 in Solidity, with tests and a deterministic deployment script. The project is built on monad-foundry, so testing against the staking precompile is straightforward. Intended as a companion to the implementation already live at 0x3f084CAF88F8894f6c83cf40b9cA7e792D9F221B on testnet — MRC-13 deliberately doesn’t anoint any single deployment as canonical, and more independent implementations help the standard get exercised across different design assumptions.

Source is published; no on-chain deployment yet. The deploy script targets the standard deterministic-deployer factory at 0x4e59b44847b379578588920cA78FbF26c0B4956C, so once broadcast it will land at the same address on every chain where the factory is present. With the current bytecode and SALT = keccak256("MRC-13:ValidatorMetadata:v1"), the predicted address is 0x610AAca1B07DCAe88602Cc836bB58a437A5791F3.

Repo: GitHub - monad-developers/validator-metadata-registry · GitHub

Notable design choices

Documenting the bits where the spec leaves room and this implementation made a specific call.

Delegation keyed by (validatorId, authority, delegate). The MRC’s “implementations MAY accept additional callers” clause is implemented as per-(validator, authority) approvals. Three properties flow from that key shape:

  • Approvals are scoped to one validator — approving a delegate for v1 doesn’t grant access to v2.
  • A staking-precompile authority rotation implicitly retires the prior authority’s delegates; the write-check’s lookup key changes.
  • setApproval itself rejects calls from any address that isn’t the validator’s current authority, so sub-delegation is structurally impossible.

This is a more restrictive shape than the alternatives I considered (per-authority only, or per-(authority,delegate) without validatorId). The trade-off is operational ergonomics — an authority running N validators needs N setApproval calls to grant the same delegate access across all of them — in exchange for tighter blast-radius semantics around rotation and per-validator policy.

Custom errors over revert strings. Unauthorized(), ValidatorNameEmpty(), ValidatorMetadataEmpty(), InvalidDelegate(). Smaller calldata on revert and clearer indexer-side decoding.

Live authority resolution on every write. No caching anywhere — the staking-precompile call happens on the write transaction, so a rotation takes effect immediately with no registry-side action.

deleteMetadata is included. Symmetric with setMetadata: same authorization, opposite direction. Useful for validators who want to retire their record without touching the staking precompile.

Deterministic deployment via the standard CREATE2 factory. Salt versioning policy: bump v1v2 in the salt string when bytecode changes in a way that should land at a fresh address.

No upgrade path. No proxy, no admin, no migration. A schema change is a new deployment at a new address — integrators track which address they consider current.

Test coverage

53 tests, including:

  • Every test case from MRC-13 Test Cases.
  • Per-Field branch coverage on updateMetadataField.
  • Event-payload assertions on every successful write.
  • Authority rotation in both directions.
  • Three fuzz tests at 1000 runs each (set-metadata persistence with arbitrary inputs, additionalInfo verbatim storage, non-authority rejection).
  • The delegation surface: zero/self-delegate rejection, no-op short-circuit in three distinct shapes (re-granting, revoking-never-approved, revoking-already-revoked), per-validator scoping, rotation invalidation, post-rotation old-authority-cannot-write.

What’s next

  • Open to feedback on the delegation model — the per-validator scoping is a deliberate choice but not the only defensible one, and reactions are welcome.
  • Tracking @ColinkaMalinka’s “observed validator status” direction with interest — that’s a consumer-side, off-chain layer on top of the registry, which feels like the right separation.
1 Like

Great to see this, and I like the companion framing. A few things in yours I think are clear improvements worth calling out:

  • Deterministic CREATE2 via the standard factory is a clean answer to the discovery question the thread kept circling: a predictable same-address deployment, with salt versioning for schema bumps. Nicer than pinning an address in an SDK.
  • Per-(validatorId, authority, delegate) delegation is a tighter blast radius than the flat per-(validator, writer) approval I shipped, and rotation implicitly retiring delegates is the right default.
  • deleteMetadata and the full Test Cases + fuzz coverage are good additions.

On my side I’ll keep the live deployment running as a second independent implementation, and focus where the durable value is and where you pointed: the consumer-side observed layer. ProofLine and MonadPulse already cross-confirm provider/asn/region against the declared infrastructure field (they agree 162/162 on asn where they overlap), kept fully off-chain so the registry stays the declared record.

One thing that might help now that there are several implementations: a shared conformance harness that runs any deployment against the formal MRC-13 Test Cases, so every impl can show the same green checklist. Happy to put that together if useful.

@ShadowOfTime1 Having formal set of tests would be super useful!

@mijovic here it is: GitHub - ShadowOfTime1/monad-mrc13-conformance: Conformance harness for MRC-13 validator metadata registry deployments on Monad: standardized behavioral checks against any live registry. · GitHub

It runs the standardized MRC-13 behavior against any deployed registry and prints a pass/fail checklist: the getMetadata/getName/hasMetadata shape, MetadataUpdated decoding, non-authority and unknown-validator rejection (via eth_call, no funds), and authority writes that persist and emit. Read-only and simulation need just an RPC and the address; the two write checks use a signer that is a validator’s authority and restore the record afterwards.

Against the testnet deployment it’s 8/8. It’s deliberately limited to the standardized surface, so delegation naming and deleteMetadata are left out. Once you broadcast yours at the deterministic address I’ll point it there too, and I’d like to align the case list with the formal Test Cases section so every implementation can show the same checklist. Naming and additions welcome.