跳转到主要内容
mip.watch
⌘K

MRC-13

Validator Metadata Registry

最终 标准轨道 MRC GitHub ↗ 论坛 ↗
构想 草案 审核中 最终审核 最终 持续更新

An on-chain registry standard for human-readable Monad validator metadata

作者
Dorde Mijovic <[email protected]> (@mijovic), Jackson Lewis
创建时间
2026-06-15
更新时间
2026年8月25日

利益相关方影响

此 MIP 为各受众群体带来的变化。严重度和操作标记由模型推导得出,并按 MIP 类型/分类设定确定性下限值。

要点速览

该提案定义了一个链上注册合约,用于存储可读的Monad验证者元数据,以便于用户识别和使用。通过允许验证者控制其元数据,解决了当前生态系统中存在的命名不一致和中心化风险。

变更内容

  • 新增链上注册合约:提供可读的验证者元数据,如名称、网站和社交链接。
  • 验证者控制元数据:验证者可以直接更新其元数据,消除中心化管理的瓶颈。
  • 支持按字段更新:允许验证者仅更新特定字段,降低了操作成本。
  • 引入JSON格式:社交链接和附加信息字段使用JSON格式,便于未来扩展。
  • 不影响现有系统:该提案为附加性,不会改变现有的质押预编译或网络行为。
⌘

开发者

智能合约与 dapp 构建者、RPC 使用者、工具开发者

该MRC引入了一个新的合约接口IValidatorMetadata,开发者需要实现该接口以支持验证者元数据的注册和更新。现有合约如果依赖于验证者元数据,可能需要重新编译或部署以适应新的接口和功能。

中 需要采取行动
◉

用户

钱包用户、EOA 持有者、dapp 访问者

此更新引入了一个链上注册表标准,用于存储可读的验证者元数据,用户在使用钱包或查看验证者信息时将看到更清晰的名称和标识。

中
◆

验证者

节点运营者、RPC 运营者、委托者

此MRC引入了一个链上注册表,允许验证者控制其元数据的可读性,提升了验证者的可识别性,但对验证者的收入和盈利能力没有直接影响。

低
✦

基金会

Monad 基金会与 Category Labs 核心开发者

此标准的实施需要协调多个客户端和合作伙伴,以确保所有参与者遵循相同的元数据注册协议。还需要更新文档以反映新的注册标准。

高 需要采取行动

2026年9月19日 03:20 生成 · 模型:gpt-4o-mini

规范

机器翻译
引用

为方便阅读的 AI 翻译,可能不准确或已过时。在治理、投票和争议中,英文原文是唯一权威文本。准确表述请参阅 GitHub 原文。

GitHub 英文原文 ↗
## 摘要

本 MRC 指定了一个链上注册合约,该合约增强了 Monad 质押预编译(位于 `0x0000000000000000000000000000000000001000`)的功能,提供可读的验证者元数据:名称、网站、描述、logo URL、一个 JSON `socials` 字段,以及一个 JSON `additionalInfo` 字段以支持向前兼容的扩展。至少,验证者自己的权威地址 — 由质押预编译报告 — 必须能够为该验证者写入元数据;实现可以自由地根据自己的授权模型授予额外调用者写入权限。该注册表提供完整记录写入和逐字段更新的功能,以及用于读取存储记录的方法。

## 动机

Monad 质押预编译是共识层验证者身份的真实来源,但它故意只暴露共识和奖励会计所需的数据(权威地址、标志、质押、佣金、公钥等)。它不提供任何可读的验证者身份信息。

钱包、区块浏览器、质押仪表板、治理用户界面和委托工具都需要通过可识别的名称和 logo 来呈现验证者,而不是通过数字 `validatorId`。如今,每个集成者独立解决这个问题 — 通常通过维护一个链下的 `metadata.json` 文件或一个集中策划的列表 — 这导致生态系统中命名不一致、链接失效或过时,以及一个集中化风险,其中一个策展人控制着验证者如何被标记给用户。

一个无权限、由验证者控制的链上注册表消除了策展瓶颈:同一个已经控制质押参数的权威密钥被允许发布验证者的元数据,任何集成者都可以直接从符合该标准的注册合约中读取它。

## 规范

本文档中的关键字 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、"SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY" 和 "OPTIONAL" 应按照 [RFC 2119](https://www.ietf.org/rfc/rfc2119.html) 和 [RFC 8174](https://www.ietf.org/rfc/rfc8174.html) 中的描述进行解释。

### 概述

合规的实现必须部署一个符合下面定义的 `IValidatorMetadata` 接口的单一合约。合约必须在调用时查询位于 `0x0000000000000000000000000000000000001000` 的 Monad 质押预编译,以确定任何给定 `validatorId` 的当前授权地址,并且必须接受来自该授权地址的写入调用。实现可以根据自己的授权规则额外接受其他调用者的写入;请参见 [授权](#authorization)。

### 接口

```solidity
interface IValidatorMetadata {
    /// 在每次成功写入验证者的元数据时发出。
    event MetadataUpdated(uint64 indexed validatorId, address indexed authority, Metadata metadata);

    /// 验证者元数据记录。有关写入规则和 `socials` 和 `additionalInfo` 字段的 JSON
    /// 约定,请参见字段语义。
    struct Metadata {
        string name;
        string website;
        string description;
        string logo;
        string socials;
        string additionalInfo;
    }

    /// `updateMetadataField` 的字段选择器。
    enum Field {
        NAME,
        WEBSITE,
        DESCRIPTION,
        LOGO,
        SOCIALS,
        ADDITIONAL_INFO
    }

    /// 用于授权解析的 Monad 质押预编译的地址。
    /// 实现必须返回 `0x0000000000000000000000000000000000001000`。
    function STAKING_PRECOMPILE() external view returns (address);

    /// 设置或替换验证者的完整元数据记录。授权调用者
    /// 和回退条件在授权和字段语义中定义。
    function setMetadata(uint64 validatorId, Metadata calldata metadata) external;

    /// 更新单个字段,保持其他字段不变。如果 `validatorId` 尚不存在记录,则回退——
    /// `setMetadata` 是唯一可以创建记录的入口点。对于 `field == SOCIALS` 或
    /// `ADDITIONAL_INFO`,调用者应传递一个 UTF-8 JSON 对象;注册表逐字存储 `value`。
    function updateMetadataField(uint64 validatorId, Field field, string calldata value) external;

    /// 读取 `validatorId` 的完整存储元数据记录,或者如果没有记录,则返回一个全默认的
    /// `Metadata` 结构。使用 `hasMetadata` 进行消歧。
    function getMetadata(uint64 validatorId) external view returns (Metadata memory metadata);

    /// 如果已为 `validatorId` 写入元数据记录,则返回 true。等同于
    /// 存储的 `name` 非空,因为每次写入时都需要 `name`。
    function hasMetadata(uint64 validatorId) external view returns (bool);

    /// 仅读取验证者的存储名称,如果未设置元数据,则返回空字符串。
    function getValidatorName(uint64 validatorId) external view returns (string memory);
}
```

### 授权

对于每个写入入口点(`setMetadata`、`updateMetadataField`),实现必须在调用时通过调用 `STAKING_PRECOMPILE()` 上的质押预编译 `getValidator(validatorId).authority` 来解析验证者的授权,并且必须在 `msg.sender` 等于该地址时接受调用。实现不得缓存或隐藏授权地址:质押预编译中的授权变更必须立即生效。

MRC-13: 验证者元数据注册表

Beyond this baseline, implementations are free to define their own authorization model and MAY accept writes from additional callers — for example, a delegated operator key, a multisig wrapper, a governance contract, or a designated metadata manager — provided that any caller not granted access under the chosen scheme is rejected. The revert reason for unauthorized callers is implementation-defined but SHOULD be a custom error (e.g. `Unauthorized()`) rather than a string.

### 字段语义

- `name` 是必需的,并且对于任何具有元数据的验证者必须非空。 当给定空的 `name` 时,`setMetadata` 必须回退。 当使用 `Field.NAME` 和空值调用时,`updateMetadataField` 必须回退。如上所述,回退原因是实现定义的,但应该是一个自定义错误(例如 `ValidatorNameEmpty()`)。
- `website`、`description`、`logo`、`socials` 和 `additionalInfo` 是可选字符串。 注册表不得验证其内容;集成者应将其视为不受信任的输入,并在呈现之前进行清理。
- `socials` 在非空时,应为一个 UTF-8 JSON 对象,其键为小写平台标识符,值为相应的个人资料 URL 或句柄,例如:

  ```json
  {
    "x": "https://x.com/monad_xyz",
    "telegram": "https://t.me/monad",
    "discord": "https://discord.gg/monad",
    "github": "https://github.com/monad-developers"
  }
  ```

  此 MRC 并未枚举平台键的集合 — 集成者应将未知键视为不透明并传递它们。 将社交信息编码为 JSON 对象(而不是在结构中命名单个社交平台)使得注册表在生态系统的社交媒体格局随时间变化时仍然可用。
- `additionalInfo` 在非空时,应为一个 UTF-8 JSON 对象。 它保留用于向前兼容的元数据扩展(例如,委托政策、签名证明、内容哈希、未来的 MRC 负载),并且此 MRC 没有定义顶级架构;下游 MRC 可以在其中定义保留的键命名空间。
- `socials` 和 `additionalInfo` 都作为原始字符串存储。 注册表不得尝试解析它们,不得拒绝语法上无效的 JSON,并且在读取时必须逐字返回它们。因此,JSON 合规性是由编写者和消费者强制执行的约定,而不是由注册表强制执行的。

### 写入前提条件

`setMetadata` 是唯一可以创建新记录的入口点。 当为没有现有记录的 `validatorId` 调用时,`updateMetadataField` 必须回退(即 `hasMetadata(validatorId)` 为 `false` 的记录)。 这个不变性使得“`name` 是必需的”规则可执行:记录不能存在空的 `name`,因为创建记录的唯一方法 — `setMetadata` — 拒绝空名称,并且在记录存在之前无法运行字段更新。

### 事件

每次成功写入时,必须发出恰好一个 `MetadataUpdated` 事件。 `metadata` 字段必须反映写入后立即可观察到的完整记录 — 对于 `updateMetadataField`,这意味着之前存储的字段加上新更新的字段。

### 读取语义

- `getMetadata`、`getValidatorName` 和 `hasMetadata` 必须不调用质押预编译。
- `STAKING_PRECOMPILE()` 必须返回 `0x0000000000000000000000000000000000001000`。
- `hasMetadata` 必须返回 `true`,当且仅当存储的 `name` 非空。 因为 `name` 不能被设置为空字符串,除非作为全默认未初始化槽的一部分,这相当于“是否曾经为该验证者写入过任何元数据且未随后置空”。
- 实现可以在此接口之外公开额外的视图函数(例如,组合的“质押信息 + 元数据”读取器),但不得更改此处定义的任何函数的语义。

### 链特性

符合此 MRC 的注册合约在部署时选择的普通合约地址上部署 — 而不是在预编译地址上 — 这两者之间没有关联,除了注册表在 `0x0000000000000000000000000000000000001000` 调用预编译以进行权限解析。

此 MRC 定义了一个接口和行为规范,而不是特定的字节码或地址。任何数量的独立部署的符合规范的实现可以在任何 Monad-EVM 网络上共存;此 MRC 不指定其中任何一个为规范实现,也不记录地址。集成者和验证者根据自己的信任和操作偏好选择要写入和读取的符合规范的部署。

任何部署仅在暴露 staking 预编译的网络上有效,地址为 `0x0000000000000000000000000000000000001000`;在预编译缺失的网络上,写入方法将回退,而通过预编译代理的读取方法将返回零记录,因此符合规范的注册表无法在此类网络上运行。

## 理由

**为什么将授权锚定到质押预编译上?** 预编译已经持有从 `validatorId` 到授权地址的规范映射,并且是唯一被共识认可的授权轮换机制。从任何其他来源(例如,对名称的 ECDSA 签名)重新推导身份将引入第二个、不同的身份系统。

**为什么将 `setMetadata` 与 `updateMetadataField` 分开?** 仅希望更改,例如,logo URL 的验证者,否则必须重新提交整个记录(包括可能很长的 `description` 和 `additionalInfo` 字段),仅仅为了修改一个短字符串。逐字段更新减少了 gas 和 calldata 成本,并降低了授权意外覆盖其他字段的机会。

**为什么 `name` 是唯一的必填字段?** 没有名称的验证者与未设置的记录无法区分(见 `hasMetadata`)。所有其他字段都有合理的空默认值——验证者可能确实没有网站、没有 logo 或没有社交存在。

**为什么使用 JSON 的 `additionalInfo` 字段?** 扩展结构是一个 ABI 破坏性更改。一个自由格式的文本字段允许未来的 MRC 层叠结构化扩展(委托政策、签名证明、IPFS CID 等),而无需新的注册部署或存储迁移。选择 JSON 而不是不透明的 `bytes` blob 是因为记录的其余部分已经是人类可读的文本,这个领域的每个链下消费者都已经会说 JSON,并且在需要时,二进制负载可以在 JSON 值中进行十六进制编码。

**为什么 `socials` 使用 JSON(而不是每个平台一个列)?** 在结构中命名特定平台将使注册锁定在今天的社交媒体格局。一个以平台标识符为键的 JSON 对象结构足够,使工具能够挑选出已知的键(`"x"`、`"telegram"` 等),而不需要规定集合;新的平台可以由验证者添加,而无需对注册进行任何更改,并且可以删除平台而不留下无效的结构字段。注册故意不解析 JSON——这在链上会很昂贵,并且会迫使规范固定特定的 JSON 方言——因此合规性在写入者和读取者之间以社会方式强制执行。

**为什么授权地址只是基线,而不是唯一的写入者?** 授权地址是每个验证者今天显然控制的唯一身份,因此以其为锚定提供了一致的、与共识对齐的默认值。但验证者有真实的理由来委托元数据管理——热钥/冷钥分离、团队操作员在不触及质押密钥的情况下轮换品牌、安全意识强的操作员的多签门控更改——强迫这些流程共享授权密钥将扩大其影响范围或将验证者推回链下策展。让实现扩展写入者集超过授权基线保留了默认路径的可审计性(任何人都可以验证授权至少是被允许的),同时为上层的操作现实政策留出空间。

**为什么在链上存储数据而不仅仅是内容哈希?** 在链上存储名称相对于验证者的 gas 预算是便宜的,消除了对外部内容寻址存储可用性的依赖,适用于名称和网站等一流字段,并允许轻量集成者在不运行 IPFS 或 HTTP 获取器的情况下读取元数据。更重的扩展负载可以使用 `additionalInfo` 来保存内容哈希。

## 向后兼容性

此 MRC 纯粹是附加的:它指定了一个新的应用层合约,并且不更改质押预编译、EVM 或任何现有的共识或网络行为。它没有引入向后不兼容的更改。

当前消费链下 `metadata.json` 文件的生态系统工具可以继续这样做。工具应在可用时迁移到从注册表读取,将链下文件视为尚未注册元数据的验证者的后备。

## 测试用例

符合规范的实现应展示以下行为:

1. 从验证者的权限调用 `setMetadata` 成功,持久化完整记录,并发出 `MetadataUpdated` 事件,携带存储的记录。
2. 从既不是验证者当前权限也未在实现自身方案下授权的地址调用 `setMetadata` 会回滚。
3. 调用 `setMetadata` 时如果 `metadata.name == ""` 会回滚,即使其他字段均非空且调用者已被授权。
4. 针对 `validatorId` 调用 `updateMetadataField` 时,如果 `hasMetadata` 为 `false`,则会回滚,无论调用地址是什么。
5. 针对每个 `Field` 变体调用 `updateMetadataField` 仅更新该字段,其他字段保持不变,并发出 `MetadataUpdated` 事件,携带完整的更新后记录。
6. 调用 `updateMetadataField(_, NAME, "")` 会回滚。使用任何其他 `field` 和空 `value` 的调用成功并清除该字段。
7. 调用 `updateMetadataField(_, ADDITIONAL_INFO, value)` 将 `value` 原样存储到 `additionalInfo` 中,注册表不执行任何 JSON 验证。
8. 在验证者的质押预编译权限从 `A` 转移到 `B` 后,`B` 的写入成功,无需对注册表采取任何行动,证明权限是实时解决的。
9. `hasMetadata(id)` 对于任何从未写入的 `id` 返回 `false`,在成功调用 `setMetadata` 后返回 `true`。
10. `STAKING_PRECOMPILE()` 返回 `0x0000000000000000000000000000000000001000`。

## 参考实现

规范性文档

论坛讨论

22 个帖子 · 13 个点赞 · 2个月前
在论坛上阅读更多 ↗
  1. @Đorđe Mijović #1 2026年6月16日 17:53

    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...

  2. @Roman Karpenko #2 2026年6月16日 19:28

    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.

  3. @Vladimir Understanding #3 2026年6月16日 22:29

    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 metadat...

  4. @Colinka | Proofoflines.org #4 2026年6月16日 22:44

    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...

  5. @badfriend #5 2026年6月17日 19:03

    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.