Agent skill

crane-natspec

This skill should be used when the user asks about "natspec", "documentation", "include-tag", "selector", "cast", "@custom:signature", "@custom:selector", "@custom:topiczero", "@custom:interfaceid", "AsciiDoc", or needs guidance on documenting Crane contracts with NatSpec and AsciiDoc include-tags.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/crane-natspec

SKILL.md

Crane NatSpec & Documentation Standards

Crane uses NatSpec combined with AsciiDoc include-tags for accurate, extractable documentation.

AsciiDoc Include-Tags

Wrap documented symbols with include-tags for documentation extraction:

solidity
// tag::MySymbol[]
/// @notice Description of the symbol
function myFunction() external { ... }
// end::MySymbol[]

Tag Format Rules

  • Tag markers must match exactly (no extra spaces inside [])
  • Tag name should match the symbol being documented
  • Use PascalCase for tag names matching type names
  • Use camelCase for function tag names

Example Usage

solidity
// tag::transfer[]
/// @notice Transfers tokens to a recipient
/// @param to_ The recipient address
/// @param amount_ The amount to transfer
/// @return success True if transfer succeeded
/// @custom:signature transfer(address,uint256)
/// @custom:selector 0xa9059cbb
function transfer(address to_, uint256 amount_) external returns (bool success);
// end::transfer[]

Custom NatSpec Tags

Functions

Tag Purpose Example
@custom:signature Canonical signature string transfer(address,uint256)
@custom:selector bytes4 selector 0xa9059cbb
solidity
/// @notice Transfers tokens
/// @custom:signature transfer(address,uint256)
/// @custom:selector 0xa9059cbb
function transfer(address to_, uint256 amount_) external returns (bool);

Errors

Tag Purpose Example
@custom:signature Canonical error signature NotOwner(address)
@custom:selector bytes4 selector 0x30cd7471
solidity
/// @notice Thrown when caller is not the owner
/// @custom:signature NotOwner(address)
/// @custom:selector 0x30cd7471
error NotOwner(address caller);

Events

Tag Purpose Example
@custom:signature Canonical event signature Transfer(address,address,uint256)
@custom:topiczero bytes32 topic0 hash 0xddf252ad...
solidity
/// @notice Emitted on token transfer
/// @custom:signature Transfer(address,address,uint256)
/// @custom:topiczero 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
event Transfer(address indexed from, address indexed to, uint256 amount);

Note: Events use @custom:topiczero (bytes32), not @custom:selector (bytes4).

ERC-165 Interfaces

Tag Purpose Example
@custom:interfaceid bytes4 interface ID 0x01ffc9a7
solidity
/// @title IERC165
/// @custom:interfaceid 0x01ffc9a7
interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Computing Values with cast

Use Foundry's cast to compute selectors and hashes:

Function Selector (bytes4)

bash
cast sig "transfer(address,uint256)"
# Output: 0xa9059cbb

Error Selector (bytes4)

bash
cast sig "NotOwner(address)"
# Output: 0x30cd7471

Event Topic0 (bytes32)

bash
cast keccak "Transfer(address,address,uint256)"
# Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

Interface ID (bytes4)

For interface IDs, prefer computing in Solidity:

solidity
bytes4 interfaceId = type(IMyInterface).interfaceId;

Or compute manually by XOR-ing all function selectors:

bash
# Get each selector
cast sig "func1(uint256)"  # 0x12345678
cast sig "func2(address)"  # 0x87654321

# XOR them in Solidity or manually
bytes4 interfaceId = 0x12345678 ^ 0x87654321;

Complete Documentation Example

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

// tag::IMyToken[]
/// @title IMyToken
/// @notice Interface for MyToken
/// @custom:interfaceid 0x36372b07
interface IMyToken {

    // tag::Transfer[]
    /// @notice Emitted when tokens are transferred
    /// @param from The sender address
    /// @param to The recipient address
    /// @param amount The amount transferred
    /// @custom:signature Transfer(address,address,uint256)
    /// @custom:topiczero 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
    event Transfer(address indexed from, address indexed to, uint256 amount);
    // end::Transfer[]

    // tag::InsufficientBalance[]
    /// @notice Thrown when transfer amount exceeds balance
    /// @param account The account with insufficient balance
    /// @param balance The current balance
    /// @param required The required amount
    /// @custom:signature InsufficientBalance(address,uint256,uint256)
    /// @custom:selector 0xcf479181
    error InsufficientBalance(address account, uint256 balance, uint256 required);
    // end::InsufficientBalance[]

    // tag::transfer[]
    /// @notice Transfers tokens to a recipient
    /// @param to_ The recipient address
    /// @param amount_ The amount to transfer
    /// @return success True if the transfer succeeded
    /// @custom:signature transfer(address,uint256)
    /// @custom:selector 0xa9059cbb
    function transfer(address to_, uint256 amount_) external returns (bool success);
    // end::transfer[]

    // tag::balanceOf[]
    /// @notice Returns the token balance of an account
    /// @param account_ The account to query
    /// @return balance The token balance
    /// @custom:signature balanceOf(address)
    /// @custom:selector 0x70a08231
    function balanceOf(address account_) external view returns (uint256 balance);
    // end::balanceOf[]
}
// end::IMyToken[]

Validation Checklist

For each documented symbol, verify:

  • Include-tags wrap the symbol correctly
  • Tag names match symbol names
  • @custom:signature matches actual signature exactly
  • @custom:selector computed correctly (functions/errors)
  • @custom:topiczero computed correctly (events)
  • @custom:interfaceid computed correctly (interfaces)
  • NatSpec params match function parameters

Additional Resources

Reference Files

  • references/natspec-examples.md - More complete examples

Quick Reference

Symbol Type Selector Tag Hash Type
Function @custom:selector bytes4
Error @custom:selector bytes4
Event @custom:topiczero bytes32
Interface @custom:interfaceid bytes4 (XOR of selectors)

Didn't find tool you were looking for?

Be as detailed as possible for better results