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(); }