NatSpec 格式

Solidity 合约可以使用一种特殊的注释形式来为函数、返回值等提供丰富的文档。这种特殊形式被称为以太坊自然语言规范格式 (NatSpec)。

注意

NatSpec 的灵感来自 Doxygen。虽然它使用 Doxygen 风格的注释和标签,但没有打算与 Doxygen 保持严格的兼容性。请仔细检查下面列出的支持标签。

此文档分为面向开发人员的消息和面向最终用户的消息。这些消息可能会在最终用户(人类)与合约交互时(例如,签署交易)向他们显示。

建议所有公共接口(ABI 中的所有内容)都使用 NatSpec 对 Solidity 合约进行完整注释。

NatSpec 包括智能合约作者将使用的注释格式,以及 Solidity 编译器能够理解的格式。下面还详细说明了 Solidity 编译器的输出,它将这些注释提取为机器可读的格式。

NatSpec 也可能包含第三方工具使用的注释。这最有可能是通过 @custom:<name> 标签实现的,一个好的用例是分析和验证工具。

文档示例

使用 Doxygen 符号格式,在每个 contractinterfacelibraryfunctionevent 上方插入文档。就 NatSpec 而言,public 状态变量等效于 function

  • 对于 Solidity,你可以选择 /// 用于单行或多行注释,或者 /** 并以 */ 结尾。

  • 对于 Vyper,使用 """ 缩进到内部内容并带有裸注释。请参阅 Vyper 文档

以下示例展示了一个使用所有可用标签的合约和函数。

注意

Solidity 编译器只解释外部或公共标签。欢迎您对内部和私有函数使用类似的注释,但这些注释不会被解析。

这在将来可能会改变。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 < 0.9.0;

/// @title A simulator for trees
/// @author Larry A. Gardner
/// @notice You can use this contract for only the most basic simulation
/// @dev All function calls are currently implemented without side effects
/// @custom:experimental This is an experimental contract.
contract Tree {
    /// @notice Calculate tree age in years, rounded up, for live trees
    /// @dev The Alexandr N. Tetearing algorithm could increase precision
    /// @param rings The number of rings from dendrochronological sample
    /// @return Age in years, rounded up for partial years
    function age(uint256 rings) external virtual pure returns (uint256) {
        return rings + 1;
    }

    /// @notice Returns the amount of leaves the tree has.
    /// @dev Returns only a fixed number.
    function leaves() external virtual pure returns(uint256) {
        return 2;
    }
}

contract Plant {
    function leaves() external virtual pure returns(uint256) {
        return 3;
    }
}

contract KumquatTree is Tree, Plant {
    function age(uint256 rings) external override pure returns (uint256) {
        return rings + 2;
    }

    /// Return the amount of leaves that this specific kind of tree has
    /// @inheritdoc Tree
    function leaves() external override(Tree, Plant) pure returns(uint256) {
        return 3;
    }
}

标签

所有标签都是可选的。下表解释了每个 NatSpec 标签的目的以及它可以使用的地方。作为特例,如果没有使用标签,则 Solidity 编译器会将 ////** 注释解释为与使用 @notice 标签相同。

标签

上下文

@title

一个应该描述合约/接口的标题

合约、库、接口、结构体、枚举

@author

作者的姓名

合约、库、接口、结构体、枚举

@notice

向最终用户解释此功能

合约、库、接口、函数、公共状态变量、事件、结构体、枚举

@dev

向开发人员解释任何额外细节

合约、库、接口、函数、状态变量、事件、结构体、枚举

@param

像 Doxygen 中一样记录参数(必须后跟参数名称)

函数、事件

@return

记录合约函数的返回值

函数、公共状态变量

@inheritdoc

从基函数复制所有缺少的标签(必须后跟合约名称)

函数、公共状态变量

@custom:...

自定义标签,语义由应用程序定义

任何地方

如果您的函数返回多个值,例如 (int quotient, int remainder),则使用多个 @return 语句,格式与 @param 语句相同。

自定义标签以 @custom: 开头,必须后跟一个或多个小写字母或连字符。但它不能以连字符开头。它们可以在任何地方使用,并且是开发人员文档的一部分。

动态表达式

Solidity 编译器会将来自 Solidity 源代码的 NatSpec 文档传递到 JSON 输出中,如本指南所述。此 JSON 输出的使用者(例如,最终用户客户端软件)可以将此直接呈现给最终用户,或者可以应用一些预处理。

例如,一些客户端软件会渲染

/// @notice This function will multiply `a` by 7

到最终用户,显示为

This function will multiply 10 by 7

如果正在调用函数并且输入 a 被分配了值 10。

继承说明

没有 NatSpec 的函数会自动继承其基函数的文档。对此的例外情况是

  • 当参数名称不同时。

  • 当存在多个基函数时。

  • 当存在一个明确的 @inheritdoc 标签,该标签指定应该使用哪个合约进行继承时。

文档输出

当由编译器解析时,如上例中所示的文档将生成两个不同的 JSON 文件。一个是供最终用户在执行函数时作为通知使用,另一个是供开发人员使用。

如果上述合约保存为 ex1.sol,则可以使用以下命令生成文档

solc --userdoc --devdoc ex1.sol

输出如下。

注意

从 Solidity 版本 0.6.11 开始,NatSpec 输出还包含 versionkind 字段。当前,version 设置为 1kind 必须是 userdev 之一。将来可能会引入新版本,弃用旧版本。

用户文档

上述文档将生成以下用户文档 JSON 文件作为输出

{
  "version" : 1,
  "kind" : "user",
  "methods" :
  {
    "age(uint256)" :
    {
      "notice" : "Calculate tree age in years, rounded up, for live trees"
    }
  },
  "notice" : "You can use this contract for only the most basic simulation"
}

请注意,用于查找方法的键是函数的规范签名,如 合约 ABI 中所定义,而不仅仅是函数名称。

开发人员文档

除了用户文档文件外,还应该生成一个开发人员文档 JSON 文件,它应该如下所示

{
  "version" : 1,
  "kind" : "dev",
  "author" : "Larry A. Gardner",
  "details" : "All function calls are currently implemented without side effects",
  "custom:experimental" : "This is an experimental contract.",
  "methods" :
  {
    "age(uint256)" :
    {
      "details" : "The Alexandr N. Tetearing algorithm could increase precision",
      "params" :
      {
        "rings" : "The number of rings from dendrochronological sample"
      },
      "return" : "age in years, rounded up for partial years"
    }
  },
  "title" : "A simulator for trees"
}