![](https://habrastorage.org/getpro/habr/upload_files/3b1/585/988/3b1585988fd8f9dd80c1a37ff0602429.jpeg)
Комментарии используются для того, чтобы объяснить что делает код. Роберт С. Мартин ("дядюшка" Боб) утверждает, что «правильное использование комментариев должно компенсировать нашу неспособность выразить что-то в коде». Поэтому комментарии делают исходный код более понятным для человека.
Почему комментарии так важны, когда дело доходит до Solidity? Потому что они помогают разобраться в работе вашего смарт контракта не только разработчикам, но и конечным пользователям.
Как писать комментарии в Solidity?
Для того, чтобы написать однострочный комментарий, можно использовать //
// This is a single line comment
Для многострочных используется /*
в комбинации с */
/*
This is a
multi-line comment
*/
Документация Solidity гласит:
Однострочный комментарий завершается любым знаком конца строки Unicode (LF, VF, FF, CR, NEL, LS или PS) в кодировке utf-8. Знак конца строки по-прежнему является частью кода, который идет после комментария. Поэтому, если он не является символом ascii (т.е. NEL, LS и PS), это приведет к ошибке парсера.
Разные типы комментариев в Solidity
В Solidity есть два основных типа комментариев: обычные и комментарии NatSpec. Так, например, в Remix IDE их можно узнать по разным цветам (зеленый используется для обычных комментариев, а синий для комментариев NatSpec).
![](https://habrastorage.org/getpro/habr/upload_files/21f/9e7/69c/21f9e769cdb6f6b2fa97c14c3987cb46.png)
Что такое комментарии NatSpec?
Контракты Solidity имеют специальную форму комментариев, которые составляют основу формата спецификации естественного языка Ethereum(Ethereum Natural Language Specification Format), также известного как NatSpec. NatSpec разрабатывается и распространяется командой Ethereum.
Формат комментариев NatSpec соответствует стилю нотации Doxygen:
Для однострочных комментариев используется
///
Для многострочных комментариев используется
/**
в сочетании с*/
Комментарии используется перед объявлением
function
,contract
,library
, interface,function
иconstructor
/// This is a Natspec single line comment
/**
This is a
Natspec multi-line
comment block
*/
Важно! Комментарии NatSpec неприменимы для переменных. Даже, если они объявлены публично и, следовательно, влияют на ABI. Подробности
Использование тегов Doxygen вместе с NatSpec
Для максимальной пользы, в работе с NatSpec стоит использовать теги Doxygen.
Doxygen — генератор документации программного обеспечения. Документация создается с помощью анализа комментариев в коде.
Фрагмент кода ниже (из документации Solidity) показывает, как используются эти теги. Теги Doxygen начинаются с @ и используются для того, чтобы, например, объяснить:
Заголовок контракта(в более понятном для человека виде)
Что делает функция
rectangle
За что отвечают параметры
w
иh
(ширина и высота прямоугольника)Что вернет функция:
s
(площадь) иp
(периметр)
pragma solidity >=0.4.0 <0.7.0;
/** @title Shape calculator. */
contract ShapeCalculator {
/** @dev Calculates a rectangle's surface and perimeter.
* @param w Width of the rectangle.
* @param h Height of the rectangle.
* @return s The calculated surface.
* @return p The calculated perimeter.
*/
function rectangle(uint w, uint h) public pure returns (uint s, uint p) {
s = w * h;
p = 2 * (w + h);
}
}
Вы можете использовать Doxygen с комментариями NatSpec в качестве инструмента для создания документации. Однако имейте в виду, что в Solidity доступны только 6 тегов Doxygen:
![](https://habrastorage.org/getpro/habr/upload_files/ab7/340/227/ab7340227728be29beca17631fbe4c92.png)
Все эти теги опциональны, но их использование имеет следующие преимущества:
Позволяет документировать функции, конструкторы, контракты, библиотеки и интерфейсы
Предоставляют данные для пользовательского интерфейса (отображают текст подтверждения, который показывается пользователям, когда они пытаются вызвать функцию).
Примечание: В настоящее время NatSpec интерпретирует теги только в том случае, если они применены к external или public значениям. Вы по-прежнему можете использовать их для своих internal и private функций, но они не будут анализироваться.
Важно помнить про два основных тега:
@notice
: информация о том, что делает функция, которая показывается пользователю во время исполнения@dev
: документация для разработчиков
Если не используются никакие теги(например, используется только ///
), то все сообщение применяется с тегом @notice
Тег @notice
, пожалуй, является самым главным тегом в NatSpec. Он предназначен для тех, кто никогда не видел исходный код. Поэтому следует избегать информации о деталях реализации кода.
Вот еще один пример использования тегов Doxygen в смарт-контракте SimpleStorage из документации Solidity:
pragma solidity >=0.4.0 <0.7.0;
/// @author The Solidity Team
/// @title A simple storage example
contract SimpleStorage {
uint storedData;
/// Store `x`.
/// @param x the new value to store
/// @dev stores the number in the state variable `storedData`
function set(uint x) public {
storedData = x;
}
/// Return the stored value.
/// @dev retrieves the value of the state variable `storedData`
/// @return the stored value
function get() public view returns (uint) {
return storedData;
}
}
Теги @param
и @return
имеют следующую спецификацию:
После
@param
должно идти имя переменной, которая использовалась в функцииПосле
@return
должно идти имя или тип переменной, которую возвращает функция
Если ваша функция возвращает несколько значений, то следует использовать @return
для каждого значения отдельно(аналогично с @param
).
Хорошим примером контракта Solidity, который элегантно использует комментарии NatSpec с Doxygen, является библиотека Buffer от Oraclize (созданная и используемая ими для своего API). Вы можете увидеть, насколько хорошо задокументированы функции append
и appendInt
с помощью тега @dev
, который точно объясняет, что именно делает каждая функция. Наконец, теги @param
и @return
помогают понять, как ведет себя функция.
Создание документации с NatSpec: введение
Компилятор Solidity автоматически создает файл JSON(метаданные контракта), который содержит информацию о скомпилированном контракте. Вы можете использовать этот файл для запроса версии компилятора, используемых источников, документации ABI и NatSpec для более безопасного взаимодействия с контрактом и проверки его исходного кода. Подробнее
Другими словами, этот JSON файл включает версию компилятора, ABI, а также документацию NatSpec. Документация пользователя и разработчика NatSpec появится в конце файла метаданных, в разделе output
(прямо под ABI):
{
version: "1",
language: "Solidity",.
compiler: {
...
},
sources:
{
...
},
settings:
{
...
},
output:
{
abi: [ ... ],
userdoc: [ ... ],
devdoc: [ ... ],
}
}
Компилятор Solidity solc
может создать документацию двух типов (в формате JSON) после компиляции вашего смарт-контракта:
Документация для разработчиков:
solc --devdoc my_contract.sol
Пользовательская документация:
solc --userdoc my_contract.sol
Создание документации с NatSpec: подготовка
Теперь, давайте посмотрим как компилятор Solidity создает документацию нашего смарт-контракта. Для этого вам нужен компилятор solc
(инструкция по установке). После установки, откройте свой терминал и следуйте приведенным ниже инструкциям:
Создайте новую папку(например, NatSpec) и пройдите в нее:
$ mkdir Natspec && cd Natspec
Создайте новый Solidity файл:
$ nano natspec.sol
Вставьте код ниже:
pragma solidity ^0.5.0;
/// @title A Geometry triangle simulator
/// @author Jean Cavallera
/// @notice Use this contract for only the most basic simulation
/// @dev Contract under development to enable floating point
contract Geometry {
struct Triangle {
uint side_a;
uint side_b;
uint hypothenuse;
}
/// @notice Math function to calculate square root
/// @dev Not working with decimal numbers
/// @param x The number to calculate the square root of
/// @return y The square root of x
function sqrt(uint x) internal pure returns (uint y) {
uint z = (x + 1) / 2;
y = x;
while (z < y) {
y = z;
z = (x / z + z) / 2;
}
}
/// @notice Calculate the hypothenuse length based on x and y
/// @dev Not working as it returns integers and not float
/// @param _a Side 1
/// @param _b Side 2
/// @return uint the hypothenuse length
function calculateHypothenuse(uint _a, uint _b) public pure returns (uint) {
return sqrt((_a * _a) + (_b * _b));
}
Triangle public my_triangle;
/// @author Jean Cavallera
/// @notice Enter the two legs of your right angle triangle
/// @dev This function modifies the state of the variable `my_triangle` and use `calculateHypothenuse()` function
/// @param _a Side 1
/// @param _b Side 2
/// @return string return to user a custom success message
function createTriangle(uint _a, uint _b) public returns (string memory) {
my_triangle = Triangle ({
side_a: _a,
side_b: _b,
hypothenuse: calculateHypothenuse(_a, _b)
});
return "new triangle created";
}
}
Создание документации с NatSpec: документация разработчика
Введите следующую команду:
solc — devdoc natspec.sol
У вас должно получиться что-то такое:
{
"author" : "Jean Cavallera",
"details" : "All function calls are currently implemented without side effects",
"methods" :
{
"calculateHypothenuse(uint256,uint256)" :
{
"details" : "Not working as it returns integers and not float",
"params" :
{
"_a" : "Side 1",
"_b" : "Side 2"
},
"return" : "uint the hypothenuse length"
},
"createTriangle(uint256,uint256)" :
{
"author" : "Jean Cavallera",
"details" : "This function modifies the state of the variable `my_triangle` and use `calculateHypothenuse()` function",
"params" :
{
"_a" : "Side 1",
"_b" : "Side 2"
},
"return" : "string return to user a custom success message"
}
},
"title" : "A Geometry triangle simulator"
}
Давайте более подробно посмотрим на этот файл:
ключи представляют собой Doxygen теги, которые мы использовали до этого:
@title
,@autor
,@param
и@return
. Единственная разница заключается в значении ключа details, которые берется из тега@dev
.значения ключей соответствуют описанию тегов из NetSpec комментариев.
Есть еще две важные вещи, которые касаются раздела devdoc в ABI:
функция включает типы передаваемых аргументов(пример:
"createTriangle(uint256,uint256)"
)показываются только public функции. Так, например, private функция
sqrt(uint x)
отсутствует в итоговом файле.
NatSpec формирует документацию только для public и external функций
Мы упоминали об этом ранее. Вот что указано в документации Solidity:
(документация Solidity): NatSpec в настоящее время интерпретирует теги только в том случае, если они применяются к external или public функциям. Вы по-прежнему можете использовать аналогичные комментарии для своих internal и private функций, но они не будут анализироваться.
Создание документации с NatSpec: пользовательская документация
Выполните следующую команду:
solc --userdoc natspec.sol
Вы должны получить что-то такое:
{
"methods" :
{
"calculateHypothenuse(uint256,uint256)" :
{
"notice" : "Calculate the hypothenuse length based on x and y"
},
"createTriangle(uint256,uint256)" :
{
"notice" : "Create a new right angle triangle using two right angle sides and calculate the hypothenuse dynamically"
}
},
"notice" : "Use this contract for only the most basic simulation"
}
Как мы видим, у нас все еще есть имя функции с ее параметрами, а также тег @notice
как для контрактов, так и для функций.
Пример: документация разработчика в Remix
Использовать Doxygen теги особенно удобно, если вы работаете с Remix.
Новая версия Remix содержит плагины, расширяющие его основную функциональность. Очень полезной функцией является "Documentation File Generator in Markdown". Она создает генерацию контракта в формате Markdown на основе NetSpec комментариев.
Откройте Remix. Кликните по кнопке "Plugin Manager".
Найдите "Solidity Documentation Generator" и активируйте плагин.
-
Новая иконка появится в левой части интерфейса. Нажмите на нее и выберите контракт, для которого вы хотите создать документацию.
Плагин сгенерирует документацию в формате Markdown. Это выглядит примерно так:
![](https://habrastorage.org/getpro/habr/upload_files/763/3b0/0b6/7633b00b68a912826dc39ef216206295.png)
Пример: пользовательская документация для отображения сообщения в UI
Кошелек может использовать пользовательскую документацию NatSpec для отображения подтверждающего сообщения пользователю всякий раз, когда он взаимодействует с контрактом, вместе с запросом авторизации для подписи транзакции.
Пример: динамические сообщения
/// @notice Send `(valueInmGAV / 1000).fixed(0,3)` GAV from the account of
/// `message.caller.address()` to an account accessible only by `to.address()`
function send(address to, uint256 valueInmGAV) {
...
}
Если пользователь (например, с адрессом 0x2334
) попытается вызвать эту функцию с to = 0x0
и valueInmGAV=4.135
, то он увидит:
Send 4.135 GAV from the account of 0.2334 to an account accessible only by 0x0
Код, заключенный в обратные кавычки, будет выполняться в среде EVM Javascript, которая имеет доступ к message
и всем параметрам функциии. Поэтому вы можете использовать любое выражение Javascript/Paperscript
для создания кастомных сообщений.
Atom плагин для авто-генерации NatSpec комментариев
NodeFactory.io разработали Atom плагин — solidity-comments. Он содержит базовые функции для создания всей шаблонной документации для вашего смарт-контракта Solidity. Его можно использовать с помощью нажатия следующей комбинации клавиш: Ctrl + Alt + G
.
Например, допустим у вас есть такой код:
pragma solidity 0.4.24;
contract SomeContract {
function test(uint _param1, uint _param2) external {
require(_param1 == 1 && _param2 == 2);
}
}
Нажмите Ctrl + Alt + G
и вы получите:
pragma solidity 0.4.24;
/// @title SomeContract
/// @notice
/// @dev
contract SomeContract {
/// @notice
/// @dev
/// @param _param1
/// @param _param2
/// @return
function test(uint _param1, uint _param2) external {
require(_param1 == 1 && _param2 == 2);
}
}
Осталось только заполнить пустые теги.
jesaiah4
я тут задумался как переодически вызывать функцию и гугл ведет в LINK , при этом как я понимаю для каждого вызова нужен не только эфир , но и LINK , а если это высокочастотная система , например раз в секунду вызывать нужно , мне нужно быть с состоянием Илон Маска для оплаты LINK ? :D