Comments in Starknet contracts

Hi,

It would be nice to have a standardized format for comments which can be used for docs, frontend UX in dapps, block explorers etc. We can take inspiration from NatSpec for solidity and vyper.
https://docs.soliditylang.org/en/v0.8.11/natspec-format.html

I do not have a strict solution to follow at this moment, but wanted to start this discussion. Like solidity, we can use something in this format:

# @notice Transfer `amount` tokens from caller to `recipient`
# @dev _transfer has all the checks and logic
# @param recipient The address to transfer to
# @param amount The amount to be transferred
# @return success If the transfer was successful or not
@external
func transfer{
        syscall_ptr : felt*, 
        pedersen_ptr : HashBuiltin*,
        range_check_ptr
    }(recipient: felt, amount: Uint256) -> (success: felt):
    let (sender) = get_caller_address()
    _transfer(sender, recipient, amount)

    # Cairo equivalent to 'return (true)'
    return (1)
end
44 Likes

I agree with this and I just visited the forum to suggest exactly this!

I think natspec like solidity (epytext in python?) is quite easy to learn and I would use that over one of the many formats used in Python (numpy-style, google-style, sphinx-style).

In the future it would be nice for tools to display the documentation alongside functions (e.g. in the explorer or wallet)

26 Likes

I drafted a standard for this as an informational SIMP. I agree keeping it as consistent with natspec as possible is worthwhile.

Simple Summary

A standard for writing comments in Cairo contracts.

Inspired by Natspec comments for Solidity.

Abstract

The following standard provides a consistent way for Cairo contracts and their functionality to be documented. I propose that initially this should just be informational, however in future it could be integrated into the Cairo compiler to allow automated documentation generation.

Motivation

A comment standard increases the readibility of contracts which makes it easier to ensure their correct functionality.

Specification

All tags are optional. The following table explains the purpose of each tag and where it may be used.

Tag Description Context
@title Description of the cairo file header
@author Name and contact details of the author(s) header
@notice Explain to an end user what this does header, storage variable, function, event, interface
@dev Explain to a developer any extra details header, storage variable, function, event, interface
@param Documents a parameter storage variable, function, event
@return Documents a return variable storage variable, function

Headers

A header comment is a comment block that can be placed at the top of each cairo file, immediately following the imports. The header contains general information about the contents of the file including a brief description and an author.

Arrays

When working with arrays, @param and @return tags should only be applied to the pointer variable and not for the length. One can document the contents of the array in this single tag.

Example Contract

# SPDX-License-Identifier: MIT
%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.starknet.common.syscalls import get_caller_address

#
# @title Simple Savings Account
# @author Vitalik Buterin - vitalik.buterin@ethereum.org
# @notice A contract to track users' savings in various pots
#

# @dev Stores the balances of each pot
# @param address: Address of the user
# @param pot_index: Index of the pot
# @return amount: The amount stored
@storage_var
func balance(address : felt, pot_index : felt) -> (amount : felt):
end

# @dev Updates a user's balance in a specified pot
# @param amount: Amount to increase the balance by
# @param pot_index: Index of the pot
@external
func increase_balance{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
    amount : felt, pot_index : felt
):
    let (address) = get_caller_address()
    let (current) = balance.read(address, pot_index)
    balance.write(address, pot_index, current + amount)
    return ()
end

Source: SIMPs/simp-4.md at main · Orland0x/SIMPs · GitHub

27 Likes

I really like this convention.

Writing contracts and libs, I couldn’t settle on a specific docstyle. And I agree with @fracek, using this in-code doc would be awesome.

20 Likes

Starting to use it I think it could be useful to also add implicit arguments and types

struct Structure:
    member m1: felt
    member m2: felt
end

# @dev Updates a user's balance in a specified pot
# @implicit syscall_ptr (felt*)
# @implicit pedersen_ptr (HashBuiltin*)
# @implicit range_check_ptr (felt)
# @param value (felt): A value to do something
# @param structure (Structure*): A pointer to a Structure
# @return res (Structure): A Structure which is not a pointer
@external
func useful_function{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
    value : felt, structure : Structure*
) -> (res : Structure):
    # code #
    return (res)
end
16 Likes

Documenting Implicit arguments would get very repetitive as the same few of them get passed to virtually every function. Also as they are implicit, I don’t see them as necessary for documenting functionality/usage.

Types are specified in the function arguments already so seems redundant to do so again in my opinion. Within the description of the parameter, one can add information about the type if deemed necessary.

15 Likes

Yeah, I agree I went a bit overboard with typing everything, we can definitely infer felt type by default.

Regarding implicit arguments, the idea behind was to have easy access to which implicit args are required (even though, as you said, they are usually the same 3 to 4 ones) and not have to go look into the library’s code everytime. But I guess an improved vscode extension could display the function implicit arguments without the need for them to be described in the docstring.

15 Likes

Hey,
Just made a pull request to put it in the cairo snippets:

So that it’ll be more easy to make them :slight_smile:

18 Likes

The proposal was merged into the repo as SIMP-4

16 Likes

An amendment to the standard to be compatible with the StarkNet 0.10.0 release.

Simple Summary

A standard for writing documentation comments in Cairo contracts.

Inspired by Natspec comments for Solidity.

Abstract

The following standard provides a consistent way for Cairo contracts and their functionality to be documented. I propose that initially this should just be informational, however in future it could be integrated into the Cairo compiler to allow automated documentation generation.

Motivation

A documentation comment standard increases the readability of contracts which makes it easier to ensure their correct functionality.

Specification

All tags are optional. The following table explains the purpose of each tag and where it may be used. Three slashes (///) should be used to mark each documentation comment instead of the two (//) used for standard comments. For multi-line documentation comments, the tag should only be used on the first line and there should be no tabulation on latter lines.

Tag Description Context
@title Description of the cairo file header
@author Name and contact details of the author(s) header
@notice Explain to an end user what this does header, storage variable, function, event, interface
@dev Explain to a developer any extra details header, storage variable, function, event, interface
@param Documents a parameter storage variable, function, event
@return Documents a return variable storage variable, function

Headers

A header comment is a comment block that can be placed at the top of each cairo file, immediately following the imports. The header contains general information about the contents of the file including a brief description and an author.

Arrays

When working with arrays, @param and @return tags should only be applied to the pointer variable and not for the length. One can document the contents of the array in this single tag.

Example Contract

// SPDX-License-Identifier: MIT

%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.starknet.common.syscalls import get_caller_address

///
/// @title Simple Savings Account
/// @author Vitalik Buterin - vitalik.buterin@ethereum.org
/// @notice A contract to track users' savings in various pots
///

/// @dev Stores the balances of each pot
/// @param address Address of the user
/// @param pot_index Index of the pot
/// @return amount The amount stored
@storage_var
func balance(address : felt, pot_index : felt) -> (amount : felt):
end

/// @dev Updates a user's balance in a specified pot
/// @param amount Amount to increase the balance by
/// @param pot_index Index of the pot
@external
func increase_balance{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
    amount : felt, pot_index : felt
):
    let (address) = get_caller_address()
    let (current) = balance.read(address, pot_index)
    balance.write(address, pot_index, current + amount)
    return ()
end

Source: SIMPs/simp-4.md at main · Orland0x/SIMPs · GitHub

14 Likes

wow i am glad to see you

9 Likes