Format and lint Solidity interface files following EigenLayer conventions. Use when the user asks to format an interface, add documentation to an interface, or create a new interface...
Format Solidity interface files following EigenLayer's established conventions for organization, documentation, and error code generation.
Every interface file should contain four interface contracts in this order:
I{ContractName}Errors - All custom errorsI{ContractName}Types - All structs and enumsI{ContractName}Events - All events (inherits Types for struct access)I{ContractName} - Main interface (inherits Errors and Events)// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
// Imports
interface I{ContractName}Errors {
// All errors with error codes
}
interface I{ContractName}Types {
// All structs and enums
}
interface I{ContractName}Events is I{ContractName}Types {
// All events
}
interface I{ContractName} is I{ContractName}Errors, I{ContractName}Events {
// All function declarations
}
Each error MUST include:
@notice describing when the error is thrown@dev Error code: 0x... with the 4-byte selector from cast sigUse cast sig to generate the error code:
cast sig "InvalidOperatorSet()"
# Output: 0x7ec5c154
interface IContractNameErrors {
/// @notice Thrown when the operator set is not valid
/// @dev Error code: 0x7ec5c154
error InvalidOperatorSet();
/// @notice Thrown when the chainId is invalid
/// @dev Error code: 0x7a47c9a2
error InvalidChainId();
/// @notice Thrown when the key type is not set for the operatorSet
/// @dev Error code: 0xe57cacbd
/// @dev Additional context about why this is required
error KeyTypeNotSet();
}
Each struct/enum MUST include:
@notice with a brief description@param for each field in structsinterface IContractNameTypes {
/// @notice A per-operatorSet configuration struct
/// @param owner the permissioned owner of the OperatorSet
/// @param maxStalenessPeriod the maximum staleness period in seconds
struct OperatorSetConfig {
address owner;
uint32 maxStalenessPeriod;
}
/// @notice Represents the status of an operator's registration
/// @param registered Whether the operator is currently registered
/// @param slashableUntil Block until which the operator remains slashable
struct RegistrationStatus {
bool registered;
uint32 slashableUntil;
}
}
Each event MUST include a singular @notice describing when the event is emitted:
interface IContractNameEvents is IContractNameTypes {
/// @notice Emitted when a generation reservation is created
event GenerationReservationCreated(OperatorSet operatorSet);
/// @notice Emitted when an operator set config is set
event OperatorSetConfigSet(OperatorSet operatorSet, OperatorSetConfig config);
/// @notice Emitted when a chainID is added to the whitelist
event ChainIDAddedToWhitelist(uint256 chainID, address operatorTableUpdater);
}
Each function in the main interface MUST include:
@notice - What the function does@param - Description for each parameter@return - Description for each return value (for view functions)@dev - Additional context (optional, but include caller requirements)@dev Reverts for: - List ALL revert conditions@dev Emits the following events: - List ALL events emittedinterface IContractName is IContractNameErrors, IContractNameEvents {
/// @notice Creates a generation reservation for cross-chain transport
/// @param operatorSet the operatorSet to make a reservation for
/// @param operatorTableCalculator the calculator contract address
/// @param config the config containing owner and staleness period
/// @dev msg.sender must be an authorized caller for operatorSet.avs
/// @dev Reverts for:
/// - CurrentlyPaused: Generation reservations are paused
/// - InvalidPermissions: Caller is not authorized
/// - InvalidOperatorSet: The operatorSet does not exist
/// - GenerationReservationAlreadyExists: Reservation already exists
/// - InvalidStalenessPeriod: The maxStalenessPeriod is invalid
/// @dev Emits the following events:
/// - GenerationReservationCreated: When the reservation is created
/// - OperatorTableCalculatorSet: When the calculator is set
/// - OperatorSetConfigSet: When the config is set
function createGenerationReservation(
OperatorSet calldata operatorSet,
IOperatorTableCalculator operatorTableCalculator,
OperatorSetConfig calldata config
) external;
/// @notice Gets the operator set config
/// @param operatorSet the operatorSet to query
/// @return The OperatorSetConfig for the given operatorSet
/// @dev You should check if an operatorSet has an active reservation first
function getOperatorSetConfig(
OperatorSet memory operatorSet
) external view returns (OperatorSetConfig memory);
}
List each revert condition with the error name and when it occurs:
/// @dev Reverts for:
/// - CurrentlyPaused: Generation reservations are paused
/// - InvalidPermissions: Caller is not an authorized caller for operatorSet.avs
/// - InvalidOperatorSet: The operatorSet does not exist in the AllocationManager
/// - GenerationReservationAlreadyExists: A generation reservation already exists
For Ownable errors, use the string format:
/// @dev Reverts for:
/// - "Ownable: caller is not the owner": Caller is not the owner
List each event with a brief description of when it's emitted:
/// @dev Emits the following events:
/// - GenerationReservationCreated: When the reservation is successfully created
/// - OperatorTableCalculatorSet: When the calculator is set for the operatorSet
/// - OperatorSetConfigSet: When the config is set for the operatorSet
View functions typically don't revert (except for input validation) and don't emit events. Document them simpler:
/// @notice Gets the active generation reservations
/// @return An array of operatorSets with active generationReservations
function getActiveGenerationReservations() external view returns (OperatorSet[] memory);
/// @notice Gets reservations by range for pagination
/// @param startIndex the start index of the range, inclusive
/// @param endIndex the end index of the range, exclusive
/// @return An array of operatorSets in the specified range
/// @dev Reverts for:
/// - InvalidRange: startIndex is greater than endIndex
/// - InvalidEndIndex: endIndex exceeds array length
function getActiveGenerationReservationsByRange(
uint256 startIndex,
uint256 endIndex
) external view returns (OperatorSet[] memory);
Reference: src/contracts/interfaces/ICrossChainRegistry.sol
This file demonstrates the full pattern with:
cast sig error codes@notice and @dev Error code: 0x... (use cast sig)@notice and @param for each field@notice describing when emitted@notice, @param, and @return (for views)@dev Reverts for:@dev Emits the following events:To generate error codes for an entire interface:
# For each error in the interface, run:
cast sig "ErrorName()"
cast sig "ErrorName(uint256)" # Include params if error has them
# Example output:
# 0x7ec5c154 # InvalidOperatorSet()
# 0x7a47c9a2 # InvalidChainId()
| Error | Typical Code | Usage |
|---|---|---|
InvalidOperatorSet() |
0x7ec5c154 |
OperatorSet doesn't exist |
InvalidPermissions() |
varies | Caller not authorized |
InvalidCaller() |
varies | Wrong msg.sender |
ArrayLengthMismatch() |
0xa24a13a6 |
Input arrays have different lengths |