Better Readability with Modifiers
Modifiers are functions you can apply to other functions. They are really useful to make.
What you will learn
- Where better readability 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.
Modifiers are functions you can apply to other functions. They are really useful to make sure some prerequisite are met before calling a function. Let’s take a simple example. In the contracts we already wrote we often have to check if the caller of a function if the owner of the contract:
function increment() public { if (owner == msg.sender) { // We check who calls the function count = count + 1; } } Imagine if our contract have multiple functions that can only be called by the owner, wouldn’t be nice to refactor this if (owner == msg.sender) part? This is where modifiers will help us. Let’s right our first modifier:
Ethereum calls and Bitcoin spends use different state models. Compare them with Bitcoin transaction structure and confirmation rules.
modifier isAdmin() { require(msg.sender == owner); _; } function increment() public isAdmin { count = count + 1; } Our modifier looks like a function. The require() function evaluate a condition and will throw an exception if the condition is not met which will stop the execution of our smart contract. The _ keyword tells the compiler to replace _ by the body of the function.
As same as a function, a modifier can accept parameters. Let’s say we could have multiple users and want to check the ownership.
For a read-only example of decoded chain data, open the Bitcoin transaction inspection tool.
modifier onlyBy(address _account) { require(msg.sender == _account); _; } function increment() public onlyBy(owner) { count = count + 1; } As you can see our modifier is more generic and let us do more.
You could also write the most generic modifier that only runs if any condition is true:
Gas accounting differs from a block-space auction. The Bitcoin fee-rate and satoshis-per-vbyte guide explains the comparison.
modifier onlyIf(bool _condition) { require(_condition); _; } function increment() public onlyIf(msg.sender == owner) { count = count + 1; } Multiple modifiers are applied to a function by specifying them in a whitespace-separated list and are evaluated in the order presented.
modifier onlyIf(bool _condition) { require(_condition); _; } function increment() public onlyIf(msg.sender == owner) onlyIf(count < 200) { count = count + 1; } In the next tutorial, we’ll learn how we can use one contract to create and interact with other contracts.
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.