BudiBadu Logo
Samplebadu

Solidity by Example: Modifiers

0.8.x

Implementing access control and validation with this code example covering function modifier definitions, the require statement for condition checking, the underscore merge point, and chaining multiple modifiers for comprehensive input validation.

Code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Owner {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    // Define a modifier
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _; // Function body is inserted here
    }

    modifier validAddress(address _addr) {
        require(_addr != address(0), "Invalid address");
        _;
    }

    function changeOwner(address _newOwner) 
        public 
        onlyOwner 
        validAddress(_newOwner) 
    {
        owner = _newOwner;
    }
}

Explanation

Function modifiers are reusable code blocks that modify function behavior, most commonly used to check preconditions before executing the function body. They reduce code duplication and improve readability by extracting common validation logic into named, reusable components. Modifiers are essential for implementing access control patterns, input validation, and state checks across multiple functions.

The special symbol _; represents the merge point where the modified function's body is inserted. Code before _; executes as a precondition check, while code after it runs as a postcondition. A function can have multiple modifiers applied in sequence, executing from left to right in the order they're listed. This allows you to compose complex validation logic from simple, focused modifiers.

The require() statement is the standard way to validate conditions in Solidity. If the condition evaluates to false, the transaction reverts immediately, undoing all state changes and returning remaining gas to the caller. The second argument provides an error message that helps users and developers understand why the transaction failed. Since Solidity 0.8.4, custom errors offer a more gas-efficient alternative to string error messages.

Code Breakdown

12-15
modifier onlyOwner encapsulates ownership check logic for reuse.
13
require(msg.sender == owner) validates caller is the owner or reverts.
14
_; is the merge point where the wrapped function's code executes.
22-25
Multiple modifiers chain together, executing onlyOwner then validAddress.