Organize Your Code and Control Access to Your Smart Contract with Modifiers
This tutorial will cover how to control who can interact with your smart contracts in a smart way using modifiers. You’ll alos learn how to make some part of your code only accessible under specific conditions like for example: only the owner of the smart contract can withdraw the funds.
Let’s get back to our previous smart contract which is a simple counter with a vairable that get incremented when a function is called. Let’s imagine that we only want ourselves to be able to increment the counter so we need to tell our smart contract our address and check if our address is the one calling the function at runtime.
To do do this, we can access anywhere in our smart contract the folowing value msg.sender which is of type address. The first step we need to do is add a member variable in our smart contract that will store the owner address. Then we’ll need to initialize the owner with the address of of the person deploying the smart contract inside of the the constructor like this:
pragma solidity 0.5.17;
contract Counter {
// Private variable of type unsigned int to keep the number of counts
uint256 private count;
address private owner;
constructor() public {
owner = msg.sender;
}
// Getter to get the count value
function getCount() public view returns (uint256) {
return count;
}
// Function to increment the value
function increment() public {
count++;
}
// Function to increment the value
function decrement() public {
count--;
}
}
Lines that are interesting are 7 and 10. Now if we’d like to only allow the owner (us) to increment or decrement the value we’ll had a condition like this:
function increment() public {
require(msg.sender == owner);
count++;
}
This works good but we need to repeat the same line of code in all the functions that restrict the access to this specific condition. As we all know, repeating code is not a good practice and that’s why Solidity comes with a feature for this case: modifiers.
Modifiers are declared inside of the smart contract and can also be inherited to child classes. They are applied to a function by specifying the list of modifiers that will be executed on the same level of the function prototype. They are containing a set of conditions that will enable or not the function to be executed.
If we rewrite the previous example with a modifier, it looks like this:
pragma solidity 0.5.17;
contract Counter {
// Private variable of type unsigned int to keep the number of counts
uint256 private count;
address private owner;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
constructor() public {
owner = msg.sender;
}
// Getter to get the count value
function getCount() public view returns (uint256) {
return count;
}
// Function to increment the value
function incrment() public onlyOwner {
count++;
}
// Function to increment the value
function decrement() public onlyOwner {
count--;
}
}
At the line 9, we define our modifier containing a condition. The _ means that we continue the execution of our function. The use of function modifiers makes any kind of restrictions highly readable.
You can add several modifiers to a function but keep in mind that the order matters. Modifiers can modify the state of the smart contract too, in fact the compiler just copy the code of the modifier inside of the function.
In the modifier we used the require function. In the next article we’ll see how to handle error and edge cases in Solidity with the require and revert function.