Function Modifiers
Modifiers wrap function bodies with reusable checks.
14.1 Basics
Modifiers wrap function bodies with reusable checks. _; marks where the function body is inserted.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Modifiers {
address public owner;
bool public paused;
uint256 private locked = 1;
error NotOwner();
error Paused();
error Reentrancy();
constructor() { owner = msg.sender; }
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
modifier whenNotPaused() {
if (paused) revert Paused();
_;
}
modifier nonReentrant() {
if (locked != 1) revert Reentrancy();
locked = 2;
_; // body runs here
locked = 1; // code after `_` runs after the body
}
modifier validAddress(address a) { // modifiers can take arguments
require(a != address(0), "zero address");
_;
}
function setPaused(bool p) external onlyOwner { paused = p; }
function transferOwnership(address newOwner)
external
onlyOwner
validAddress(newOwner) // applied left to right
{
owner = newOwner;
}
function withdraw() external whenNotPaused nonReentrant { /* ... */ }
}14.2 Rules and tips
Modifiers are applied in the order listed; each _ executes the next modifier or the body.
A return in the function body exits only the body; code after _ in the modifier still runs.
Modifiers can be virtual and overridden in derived contracts.
Modifier code is inlined at every use — for large modifiers used many times, call an internal function from the modifier to reduce bytecode size:
Avoid side effects (external calls) in modifiers; they hide control flow.
modifier onlyOwner() { _checkOwner(); _; }
function _checkOwner() internal view { if (msg.sender != owner) revert NotOwner(); }