Solidity Quick Tip: Use Modifiers To Abstract Common Logic Away

Solidity Quick Tip: Use Modifiers To Abstract Common Logic Away

How To Not Bloat Your Function Bodies With Assertions And More

Have you ever seen the need arise to apply certain assertions over and over again? Something like below, for example, when instances of contracts have certain owners?

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

contract MyContract {
  address private _owner;

  constructor() {
    _owner = msg.sender;
  }

  function ownerOnlyAccess() public pure returns (uint8) {
    require(msg.sender == _owner, "Access only for owner");
    return 0;
  }
}

This is a lot of code to establish a foundation to make the check actually required. Doing this over and over again costs even more code and thus also gas.

Gladly, Solidity gives you ways to abstract all this away and even move assertions out of your functions' bodies.

Enter Modifiers

Modifiers modify the behavior of functions. They are added to the functions' prototypes and are applied under certain circumstances.

Modifiers make the most sense when implemented in a base contract that other contracts can derive from.

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

contract Ownable {
  address private _owner;

  constructor() {
    _owner = msg.sender;
  }

  // the 'modifier' keyword marks this function as a modifier.
  modifier onlyOwner() {
    require(msg.sender == _owner, "Access only for owner");
    // the underscore is actually a special character that tells
    // the Solidity compiler to inline the body of the function
    // this modifier is applied to.
    _;
  }
}

You can use this base class and its modifier like this then:

// SPDX-License-Identifier: MIT

pragma solidity >=0.7.0 <0.9.0;

import "@yourLib/Ownable.sol";

// 'is' tells the Solidity compiler that MyContract inherits from Ownable.
contract MyContract is Ownable {
  constructor() {
  }

  // pay attention to the modifier 'onlyOwner' in the function
  // prototype. 
  // This enables the modifier for this function.
  function ownerOnlyAccess() public view onlyOwner returns (uint8) {
    // whenever this function is called, onlyOwner will run first,
    // and then the code within this function.
    return 0;
  }
}

You can apply the modifier to as many or as few functions as you want to. It saves you from repeating code over and over again. It also frees your functions' bodies from many calls that have nothing to do with the actual business logic.

The Whole Tip As An Image

If you like visual content more, or if you want to store it for later, I put all this into one single image for you. I hope you like it!

A picture showcasing the above code

Before You Leave

If you would love to read even more content like this, feel free to visit me on Twitter or LinkedIn.

I'd love to count you as my ever-growing group of awesome friends!