.claude/skills/crane-natspec/SKILL.md
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.
npx skillsauth add cyotee/crane crane-natspecInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Crane uses NatSpec combined with AsciiDoc include-tags for accurate, extractable documentation.
Wrap documented symbols with include-tags for documentation extraction:
// tag::MySymbol[]
/// @notice Description of the symbol
function myFunction() external { ... }
// end::MySymbol[]
[])// 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[]
| Tag | Purpose | Example |
|-----|---------|---------|
| @custom:signature | Canonical signature string | transfer(address,uint256) |
| @custom:selector | bytes4 selector | 0xa9059cbb |
/// @notice Transfers tokens
/// @custom:signature transfer(address,uint256)
/// @custom:selector 0xa9059cbb
function transfer(address to_, uint256 amount_) external returns (bool);
| Tag | Purpose | Example |
|-----|---------|---------|
| @custom:signature | Canonical error signature | NotOwner(address) |
| @custom:selector | bytes4 selector | 0x30cd7471 |
/// @notice Thrown when caller is not the owner
/// @custom:signature NotOwner(address)
/// @custom:selector 0x30cd7471
error NotOwner(address caller);
| Tag | Purpose | Example |
|-----|---------|---------|
| @custom:signature | Canonical event signature | Transfer(address,address,uint256) |
| @custom:topiczero | bytes32 topic0 hash | 0xddf252ad... |
/// @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).
| Tag | Purpose | Example |
|-----|---------|---------|
| @custom:interfaceid | bytes4 interface ID | 0x01ffc9a7 |
/// @title IERC165
/// @custom:interfaceid 0x01ffc9a7
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
castUse Foundry's cast to compute selectors and hashes:
cast sig "transfer(address,uint256)"
# Output: 0xa9059cbb
cast sig "NotOwner(address)"
# Output: 0x30cd7471
cast keccak "Transfer(address,address,uint256)"
# Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
For interface IDs, prefer computing in Solidity:
bytes4 interfaceId = type(IMyInterface).interfaceId;
Or compute manually by XOR-ing all function selectors:
# Get each selector
cast sig "func1(uint256)" # 0x12345678
cast sig "func2(address)" # 0x87654321
# XOR them in Solidity or manually
bytes4 interfaceId = 0x12345678 ^ 0x87654321;
// 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[]
For each documented symbol, verify:
@custom:signature matches actual signature exactly@custom:selector computed correctly (functions/errors)@custom:topiczero computed correctly (events)@custom:interfaceid computed correctly (interfaces)references/natspec-examples.md - More complete examples| 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) |
development
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
documentation
Write to contracts and send transactions. Use when executing state-changing contract functions.
development
HTTP and WebSocket transports for blockchain connectivity. Use when configuring network connections.
data-ai
Read contract data with type-safe ABI. Use when querying smart contract view/pure functions.