Learning Objectives – after this chapter you will be able to:
  • Write modifiers with and without arguments.
  • Explain the role and position of the _; placeholder (merge wildcard).
  • Apply several modifiers to one function and predict their order.
  • Use common modifier patterns such as onlyOwner, state checks and a reentrancy guard.
Solidity Modifiers
  • A function modifier is reusable code that changes the behaviour of a function – most often it checks a condition before the function runs.
  • If the condition is not met, the modifier reverts and the function body is not executed.
  • Modifiers can also run code after the function body, and they keep repeated checks (such as “only the owner may call this”) in one place.
  • All course projects use modifiers, e.g. checkBlockAdmin() and checkVoterCasting() in the Election System.
Two Variations of a Function Modifier

1. Function modifier without arguments:

modifier modifierName() {
    // checks / action to be taken
    _;
}

2. Function modifier with arguments:

modifier modifierName(uint arg) {
    // checks using arg
    _;
}

Apply a modifier by writing its name in the function header: function withdraw() public onlyOwner { ... }. Parentheses are optional when there are no arguments.

What is the Merge Wildcard ( _; )?
  • The _; symbol is called the placeholder or merge wildcard. During compilation it is replaced by the body of the function the modifier is applied to.
  • Control moves to the function body at the point where _; appears.
  • Code placed before _; runs before the function (the usual place for checks); code placed after _; runs after the function body.
  • Without _; the function body would never run, so every modifier that should let the function execute must contain it. It may appear more than once (the body then runs more than once), which is rarely useful.
  • A return inside the function body leaves only the body; any modifier code after _; still executes.
Several Modifiers on One Function

Modifiers are applied in the order they are written. In function f() public onlyOwner whenOpen { ... }, onlyOwner runs first; its _; runs whenOpen, whose _; runs the body. Like functions, modifiers can be inherited and overridden using virtual/override.

Example : Common Modifier Patterns
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Ticketing {
    address public owner;
    bool public saleOpen = true;
    uint public sold;
    bool private locked;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {                    // without arguments
        require(msg.sender == owner, "Only owner");
        _;
    }

    modifier whenOpen() {
        require(saleOpen, "Sale closed");
        _;
    }

    modifier costs(uint price) {              // with an argument
        require(msg.value == price, "Wrong amount");
        _;
    }

    modifier nonReentrant() {                 // code before AND after _;
        require(!locked, "No re-entry");
        locked = true;
        _;
        locked = false;
    }

    function buy() external payable whenOpen costs(0.01 ether) {
        sold += 1;
    }

    function closeSale() external onlyOwner {
        saleOpen = false;
    }

    function withdraw() external onlyOwner nonReentrant {
        (bool ok, ) = payable(owner).call{value: address(this).balance}("");
        require(ok, "Transfer failed");
    }
}
Key Takeaways
  • Modifiers package reusable checks; if a check fails, the function body does not run.
  • _; marks where the function body is inserted – checks before, clean-up after.
  • Multiple modifiers run left to right; modifiers can take arguments.
Download | Print      E-Notes

The PDF E-Notes are the earlier printable version of this chapter. The notes on this page are the latest, revised version.

Video : Function Modifiers in Solidity
Resource File
Question / Answer (15 questions)

Answer : A modifier is reusable code that changes the behaviour of functions it is applied to – typically checking a condition before the function body runs and reverting if it is not met.

Answer : The _; symbol (also called the placeholder). It is replaced by the body of the function the modifier is applied to, marking where that body executes.

Answer : modifier onlyOwner() { require(msg.sender == owner, "Only owner"); _; }, applied as function withdraw() public onlyOwner { ... }.

Answer : modifier costs(uint price) { require(msg.value == price, "Wrong amount"); _; }, used as function buy() external payable costs(0.01 ether) { ... }.

Answer : The require (or revert) inside the modifier reverts the transaction, so the function body is not executed and no state changes are kept.

Answer : That code runs after the function body finishes, which is useful for clean-up such as unlocking a reentrancy guard.

Answer : The function body is never executed when that modifier is applied, because there is no place where the body is inserted.

Answer : In the order they are written in the function header, from left to right; each modifier’s _; continues to the next modifier and finally to the function body.

Answer : No. return leaves only the function body; the remaining modifier code after _; still runs.

Answer : It sets a lock before the function body and clears it afterwards, so the function cannot be re-entered while it is still running – protecting against reentrancy attacks.

Answer : Access control (onlyOwner, onlyAdmin), state checks (whenOpen, auction not ended), validating payments (costs) and reentrancy protection.

Answer : Yes. Derived contracts inherit modifiers and can override them if they are marked virtual, using the override keyword.

Answer : They keep repeated checks in one place, make functions shorter and easier to read, and reduce the chance of forgetting a check.

Answer : checkBlockAdmin(), which allows only the admin to view results and counts, and checkVoterCasting(), which stops an address from voting twice.

Answer : No. Both onlyOwner and onlyOwner() are accepted.
MCQ Test : Check Your Understanding (5 questions)

Select an option and press Check Answer, or answer all questions and press Submit Test to see your score. Each answer comes with an explanation.

Q1. In a modifier, the symbol _; represents:

Show Answer

Correct Answer : B. The function body being inserted
_; is the placeholder for the function body.

Q2. Code written AFTER _; in a modifier runs:

Show Answer

Correct Answer : A. After the function body
It executes once the body has finished.

Q3. function f() public onlyOwner whenOpen – which modifier runs first?

Show Answer

Correct Answer : D. onlyOwner
Modifiers run left to right.

Q4. If a require inside a modifier fails:

Show Answer

Correct Answer : C. The whole call reverts
The revert stops the call and undoes changes.

Q5. Which modifier pattern protects against reentrancy?

Show Answer

Correct Answer : B. nonReentrant
A lock set before and cleared after the body prevents re-entry.

Bibliography/References

The notes, questions and MCQs on this page are original explanations written for this course. The works listed below were consulted and are cited for attribution and further reading. Product names, logos and trademarks belong to their respective owners. Short quotations, where used, are marked and attributed.

  1. Solidity Team. (n.d.). Contracts (creating contracts, visibility and getters, function modifiers, constant and immutable, functions, events, custom errors, inheritance, abstract contracts, interfaces, libraries). Solidity Documentation. https://docs.soliditylang.org/en/latest/contracts.html
  2. Solidity Team. (n.d.). Security Considerations. Solidity Documentation. https://docs.soliditylang.org/en/latest/security-considerations.html
  3. OpenZeppelin. (n.d.). OpenZeppelin Contracts Documentation. https://docs.openzeppelin.com/contracts/
  4. GeeksforGeeks. (n.d.). Solidity – Function Modifiers. https://www.geeksforgeeks.org/solidity-function-modifiers/
  5. Modi, R. (2018). Solidity Programming Essentials: A beginner’s guide to build smart contracts for Ethereum and blockchain. Packt Publishing. ISBN 978-1-78883-138-3.