- name
- natspec-standards
- description
- NatSpec documentation standards for Solidity contracts. Use when writing or reviewing contract documentation. Every public and external function must have NatSpec. Covers all tags, formatting conventions, and complete examples.
# NatSpec Standards
## Required Documentation
Every public and external function **must** have NatSpec. Internal functions that are non-trivial should also be documented.
## Tags Reference
| Tag | Context | Description |
|-----|---------|-------------|
| `@title` | Contract/interface | Title of the contract |
| `@author` | Contract/interface | Author name or team |
| `@notice` | Contract/function/event/error | User-facing explanation (shown in etherscan) |
| `@dev` | Contract/function/event/error | Developer-facing technical details |
| `@param` | Function/event/error | Describes a parameter |
| `@return` | Function | Describes a return value |
| `@inheritdoc` | Function | Inherits docs from parent contract |
| `@custom:tag` | Any | Custom metadata (e.g., `@custom:security-contact` is mandatory) |
## Contract-Level Documentation
```solidity
/// @title Staking Vault
/// @author Uniswap Labs
/// @notice Handles staking deposits and reward distribution for protocol governance tokens.
/// @dev Uses ERC-4626 vault standard with custom reward distribution.
/// Storage layout is proxy-compatible (see storage-layout skill).
/// @custom:security-contact security@uniswap.org
contract StakingVault is ERC4626, Ownable2Step, ReentrancyGuard {
// ...
}
```
## Function Documentation
```solidity
/// @notice Deposits tokens into the vault and mints shares to the caller.
/// @dev Follows CEI pattern. Emits {Deposited} event. The share calculation
/// uses the current exchange rate, which may be manipulated in the same
/// block — see economic-attack-vectors for first-depositor defense.
/// @param token The address of the ERC-20 token to deposit.
/// @param amount The amount of tokens to deposit (in token's native decimals).
/// @return shares The number of vault shares minted to the caller.
function deposit(address token, uint256 amount)
external
nonReentrant
whenNotPaused
returns (uint256 shares)
{
if (token == address(0)) revert ZeroAddress();
if (amount == 0) revert ZeroAmount();
shares = convertToShares(amount);
_mint(msg.sender, shares);
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
emit Deposited(msg.sender, token, amount, shares);
}
```
## Multiple Return Values
Each return value gets its own `@return` tag, in order.
```solidity
/// @notice Returns the position details for a given position ID.
/// @param positionId The unique identifier of the position.
/// @return owner The address that owns the position.
/// @return collateral The amount of collateral deposited (in token decimals).
/// @return debt The amount of debt owed (in token decimals).
/// @return healthFactor The position's health factor (18 decimals, < 1e18 = liquidatable).
function getPosition(uint256 positionId)
external
view
returns (
address owner,
uint256 collateral,
uint256 debt,
uint256 healthFactor
)
{
// ...
}
```
## @inheritdoc
Use `@inheritdoc` to inherit documentation from a parent interface or abstract contract. Add `@dev` for implementation-specific details.
```solidity
interface IVault {
/// @notice Withdraws tokens by burning vault shares.
/// @param shares The number of shares to burn.
/// @return amount The number of tokens returned to the caller.
function withdraw(uint256 shares) external returns (uint256 amount);
}
contract Vault is IVault {
/// @inheritdoc IVault
/// @dev Applies a withdrawal fee of 0.1% (10 bps). The fee is retained
/// in the vault, increasing the share price for remaining holders.
function withdraw(uint256 shares) external override returns (uint256 amount) {
// ...
}
}
```
## Event Documentation
```solidity
/// @notice Emitted when a user deposits tokens into the vault.
/// @param user The address of the depositor.
/// @param token The address of the deposited token.
/// @param amount The amount deposited (in token's native decimals).
/// @param shares The number of vault shares minted.
event Deposited(address indexed user, address indexed token, uint256 amount, uint256 shares);
```
## Error Documentation
```solidity
/// @dev Thrown when the oracle price feed returns data older than the staleness threshold.
/// @param feed The address of the Chainlink price feed.
/// @param updatedAt The timestamp of the last price update.
/// @param threshold The maximum allowed age in seconds.
error Oracle_StalePrice(address feed, uint256 updatedAt, uint256 threshold);
```
## Custom Tags
```solidity
/// @custom:security-contact security@protocol.xyz
/// @custom:oz-upgrades-from StakingVaultV1
/// @custom:storage-location erc7201:protocol.storage.StakingVault
contract StakingVaultV2 is StakingVaultV1 {
// ...
}
```
## Modifier Documentation
```solidity
/// @dev Restricts function access to the designated oracle updater.
/// Reverts with {Unauthorized} if caller is not the updater.
modifier onlyUpdater() {
if (msg.sender != updater) revert Unauthorized();
_;
}
```
## Struct Documentation
```solidity
/// @notice Represents a user's staking position.
/// @dev Packed into 2 storage slots (64 bytes). See storage-layout skill.
/// @param amount The staked token amount (18 decimals).
/// @param rewardDebt Used for reward accounting (scaled by ACC_PRECISION).
/// @param lockEnd The timestamp when the lock period expires.
/// @param boostMultiplier The user's boost factor (100 = 1x, 200 = 2x).
struct StakeInfo {
uint256 amount;
uint256 rewardDebt;
uint48 lockEnd;
uint16 boostMultiplier;
}
```
## NatSpec Checklist
- [ ] Every contract has `@title`, `@author`, `@notice`
- [ ] Every public/external function has `@notice`, `@param`, `@return`
- [ ] Complex functions have `@dev` with implementation details
- [ ] Events have `@notice` and `@param` for each parameter
- [ ] Custom errors have `@dev` explaining trigger conditions
- [ ] `@inheritdoc` used for interface implementations
- [ ] `@custom:security-contact` on all deployable contracts
- [ ] No redundant docs (don't restate what the code obviously does)
- [ ] Units specified in `@param`/`@return` (decimals, bps, seconds)
- [ ] Cross-references to related skills/patterns where helpful
View on GitHub