This section describes modifier modifiers commonly used in Solidity.
What is the modifier modifiers anyway?
A modifier is a "modifier that defines a process to be performed before executing a function".
For example, before a function is executed, "I want to check whether the caller of the function is the owner of the contract or not". The modifier is then qualified to the function.
By standardizing the processing to be performed prior to function execution as a modifier, it is possible to pre-process any function by simply modifying the modifier, which has the advantage of allowing pre-processing to be used in any function.
There are two ways to write modifier modifiers: no or with arguments.
No arguments
// define modifier
modifier modifier name() {
process
_;
}
// modifier modifier to function (the process defined by modifier will be called before this function is executed)
function function name() access modifier modifier name {
}
First, define the pre-processing that you want to use commonly in each function as a modifier.
The "_; (underscore semicolon)" is important here.
This means "continue processing". If you want to continue processing a function that modifies a modifier, you should add it. (Although it depends on the use of the modifier, I think it is basically necessary to add it in most cases.)
Then, the modifier is added to the function that you want to call the process defined by the modifier in advance.
With arguments
// define modifier
modifier modifier name(argument) {
process
_;
}
// modifier modifier to function (the process defined by modifier will be called before this function is executed)
function function name() access modifier(argument) modifier name {
}
First, the modifier side, simply with arguments, is the same as in the previous description.
The function side is also qualified with a modifier that includes arguments.
Sample Code
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Test {
address owner;
constructor() {
owner = msg.sender;
}
// Define modifier (no arguments)
modifier onlyOwner {
require (msg.sender == owner);
_;
}
// Define modifier (with arguments)
modifier isAdult(uint age) {
require(age >= 18);
_;
}
// The modifier (onlyOwner) process is executed before the sayHi function is executed
function sayHi() public onlyOwner view returns(string memory) {
return "Hi Owner!";
}
uint myAge = 20;
// The modifier (isAdult) process is executed before the buyBeer function is executed
function buyBeer() public isAdult(myAge) view returns(string memory) {
return "Cheers!";
}
}
If there is a process that you want to call in any function, such as checking for ownership, use a modifier modifier to make it common. It is nonsense to write the same process for each function, and above all, it makes the code less readable and maintainable.