Solidity Function Modifiers

whiteboard crypto logo
Published by:
Whiteboard Crypto
on

Modifiers are keywords added to a function in Solidity, which allows the developer to create a process of code to run before and after the function it is applied to. In general, Modifiers are used to control access or check for important requirements before finishing a function. Here is an example of a modifier:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

contract modifierExample {
    
    string public name = "Jerry";
    address public owner = 0x0fC5025C764cE34df352757e82f7B5c4Df39A836;

    modifier beforeFunction{
        name = "Tom";
        _;
    }

    modifier afterFunction{
        _;
        name = "Jeff";
    }

    function testFunction() public beforeFunction afterFunction{
        name = "Sky";
    }


    modifier onlyOwner{
        require(msg.sender == owner, "You're not the owner!");
        _;
    }

    function tryToCall() public onlyOwner{
        name = "You're the Owner!";
    }

}

In the code above, we have created 3 modifiers. The first 2 modifiers are named “beforeFunction” and “afterFunction”, and the only thing they do is reassign the value of the variable “name” to either “Tom” or “Jeff”.

The difference between the “beforeFunction” modifier and the “afterFunction” modifier is the ordering of the variable reassignment and the merge wildcard. In “beforeFunction”, the variable name is reassigned to Tom, and then the rest of the function is called. In “afterFunction”, the function is applied first, then name is reassigned. The result is that variable name goes through 3 changes when “testFunction” is called:

  1. Name is initialized as Jerry
  2. Name is reassigned to Tom (in the “beforeFunction” modifier)
  3. Name is reassigned to Sky (in the function body itself)
  4. Name is reassigned to Jeff (in the “afterFunction” modifier)

The next modifier that we created was named “onlyOwner”. This modifier only contains a require statement that checks that msg.sender is equal to the variable named “owner” (which we initialized in the beginning of the contract). This modifier can be easily applied to any function to ensure that anyone who calls the function is the owner. Any other callers will receive the “You’re not the owner” error message and the transaction will revert. You can try it yourself by calling the “tryToCall” function!

When creating a modifier, you must use the keyword “modifier” to start, and then immediately follow it with a name for the modifier. After this, the body of the modifier is enclosed with curly brackets. The modifier must contain an underscore with an semicolon somewhere in the body.

The underscore in the modifier body is called the “merge wildcard”. It represents the full function that the modifier is applied to. You can think of it as a copy/paste of the actual function you apply it to, with certain code being ran before and after that function.

This brings up the question that many have asked “why would you use a modifier instead of just writing a function?”

One of the benefits of using a modifier over a function is that the developer can write code to run before and after the original function, which would be difficult or lengthy with the use of regular functions. Modifiers can also be used to reduce duplicate or very similar code, thus reducing the total gas cost of a contract.

Using Multiple Modifiers

When you apply two or more modifiers to a function, they are executed in the order they are added (meaning left to right). All of the modifier contents in the first modifier will be computed up until the underscore, then it will move to the next modifier and apply the same pattern, until all modifiers have been completed. After that, the function itself will be computed, and then finally all the code in the first modifier after the underscore will be computed, moving on to the next modifier and so on.

Passing Arguments to Modifiers

You can also pass arguments and information through modifiers to the body of the modifier. In the example below, I am creating an “onlyOwner” modifier that accepts and address and compares it to the caller of the function. If you want to change who can access this function, you just need to change the address in the function modifier.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

contract modifierArgumentExample {
    
    string public name = "not set";


    modifier onlyOwner (address addy){
        require(msg.sender == addy, "You're not the owner!");
        _;
    }

    function tryToCall() public onlyOwner(0x9d83e140330758a8fFD07F8Bd73e86ebcA8a5692){
        name = "You're the Owner!";
    }

}

Modifier Inheritance

Here is a simple contract that shows how you can inherit a modifier from another contract:

//SPDX-License-Identifier: MIT
pragma solidity 0.8.13;


contract modifierInheritance{

    address public owner;

    constructor(){
        owner = msg.sender;
    }

    modifier onlyOwner(){
        require(msg.sender == owner, "You're not the owner");
        _;
    }

}

contract inheritTheModifier is modifierInheritance{
    
    function sayHi() public view onlyOwner returns(string memory){
        return "hi";
    }
}

If you deploy the contract named “inheritTheModifier”, you’ll see that you can utilize the “onlyOwner” modifier that was originally created in the first contract named “modifierInheritance”. In this case, once you deploy the contract, if you call “sayHi” as a the creator, it will return a string. However, if you change accounts and attempt to call the same function, it will return an error notifying you that you’re not the owner.

When to use a Modifier in Solidity?

  1. Checking Permissions (onlyOwner and Admins)
  2. Reentrancy
  3. Checking EOA (onlyHuman)
  4. Validate Inputs
whiteboard crypto logo

WhiteboardCrypto is the #1 online resource for crypto education that explains topics of the cryptocurrency world using analogies, stories, and examples so that anyone can easily understand them. Growing to over 870,000 Youtube subscribers, the content has been shared around the world, played in public conferences and universities, and even in Congress.