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.

What you will learn

  • Where organize your code and control access to your smart contract with modifiers fits into an Ethereum application.
  • Which assumptions should be tested before a mainnet deployment.
  • What to read next when this concept is working.

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.

Turn the example into production evidence

A working demo is the beginning of verification, not the end. Add tests for failure paths, inspect every permission, and record the chain, contract address, compiler, and dependency versions used for the deployment.

Check behavior

Test expected inputs, boundary values, reverts, events, and calls made to other contracts.

Check operations

Plan key storage, monitoring, pause or upgrade authority, and a response if an assumption stops being true.

Continue from Organize Your Code and Control Access to Your Smart Contract with Modifiers