Ethereum Development: Interfaces and Function Modifiers
Tags: blockchain, ethereum, solidity
Published: 2018-05-13 20:58:48

---
title: Ethereum Development: Interfaces and Function Modifiers
published: true
description: A look at Interfaces and Function Modifiers in Ethereum's programming language Solidity 
cover_image: https://thepracticaldev.s3.amazonaws.com/i/ghew5sns0ydqfgovhwsr.jpg
tags: blockchain, ethereum, solidity
---

## Introduction

In my <a href="https://dev.to/damcosset/ethereum-development-getting-started-m09" target="_blank">last article</a>, we got started with Ethereum development by using Truffle and the Ganache command line. In this article, we will use this environment to explore two important concepts in Solidity: Interfaces and Function Modifiers.

## Setting things up

Assuming you have Truffle and ganache-cli already installed, create a new folder and run `truffle init` inside. Refer to the <a href="https://dev.to/damcosset/ethereum-development-getting-started-m09" target="_blank">last article</a> if you haven't done that already. We will create two contracts in the *contracts* folder *truffle* just created. Our example will be very simple.

- Answers.sol

```
pragma solidity ^0.4.18;

contract Answers {
	uint answerUniverse;

	function setAnswerUniverse(uint _answer) external {
		answerUniverse = _answer;
	}

	function getAnswerUniverse() public view returns (uint){
		return answerUniverse;
	}
}

```

- Questions.sol

```
pragma solidity ^0.4.18;

contract AnswersInterface {
	function getAnswerUniverse() public view returns (uint);
}

contract Questions {
	AnswersInterface answersContract;

	function setAnswersContractAddress(address _address) external{
		answersContract = AnswersInterface(_address);
	}

	function whatIsTheAnswerUniverse() public view returns (uint){
		uint answer = answersContract.getAnswerUniverse();
		return answer;
	}

}
```

The Answers.sol contract is very simple. There is a getter and a setter for one variable *answerUniverse*. Note, because it is important, that the setter is *external*, meaning it has to be called from **outside** the contract, and the getter is public, meaning everyone can call it.

The Questions.sol contract contains two things: the Questions contract, and the AnswersInterface interface. So, what is an interface? An interface allows you to talk to another contract on the blockchain. As you can see, to define an interface, you start out like a regular contract, with the *contract* keyword. Inside this contract, you only define the functions you want to interact with, without their bodies. Those functions need to be public or external so we can call them from outside the original contract. You couldn't interact with private or internal functions of course.

Inside our Questions contract, we create an interface instance in *answersContract*. The function *setAnswersContractAddress* will tell our contract where to look for the original Answers contract. The function *whatIsTheAnswerUniverse* retrieves the variable *answerUniverse* in the Answers contract.

*Note:* Of course, we will need to set the contract's address before retrieving the variable. If not, we wouldn't know where to look on the blockchain!

- Next, in the *truffle-config.js* file: 

```javascript
module.exports = {
	networks: {
			development: {
					host: '127.0.0.1',
					port: 7545,
					network_id: '*'
			}
	}
};


```

For Windows users, you will have to remove the truffle.js file to avoid conflicts. For others, you can keep both and put this code in truffle.js, or do like a Windows user, doesn't matter.

- Next, in the *migrations* folder, create two files: *2_deploy_questions.js* and *3_deploy_answers.js*.

- 2_deploy_questions.js

```javascript
var Questions = artifacts.require("Questions")

module.exports = function(deployer) {
	deployer.deploy(Questions)
};

```

- 3_deploy_answers.js

```javascript
var Answers = artifacts.require("./Answers.sol")

module.exports = function(deployer) {
  deployer.deploy(Answers)
}

```

## Deplooooooyyy

Everything is ready now. Open a new terminal window and run `ganache-cli -p 7545`.
Go back to the project's folder and run:

- `truffle compile`
- `truffle migrate --network development`
- `truffle console --network development`

Now, we can play with our contracts and our interface. First, create an instance for each contract:

```
truffle(development)> Questions.deployed().then(inst => Questions = inst)
truffle(development)> Answers.deployed().then(inst => Answers = inst)
```

After launching the Answers instance, you will see some stuff appear in the console. There will be an *address* field. This is the address of the Answers' contract. This is what we needed to call the *setAnswersContractAddress* function:

`truffle(development)> Questions.setAnswersContractAddress('0x2e91a07090cfbbc0839e0d76d8110e2518bae18c')`

**Note:** Of course, replace the address with whatever address you will find in that field.

Now, let's set the *answersUniverse* variable in the Answers contract:

`truffle(development)> Answers.setAnswerUniverse(76)`

And retrieve it from the Questions contract:

```
truffle(development)> Questions.whatIsTheAnswerUniverse().then(answer => answer.toNumber())
76
```

Let's modify the answer, and retrieve it again:

```
truffle(development)> Answers.setAnswerUniverse(42)
truffle(development)> Questions.whatIsTheAnswerUniverse().then(answer => answer.toNumber())
42
```

Tadaaaaaa! That's an interface for you :)

## Function modifiers

Now, you might have seen a security issue in our project. The function *setAnswersContractAddress* is external, meaning that everyone can call it from outside the contract. So, anybody could call the function and change the address!!! No good. To solve this, we will add a function modifier. A modifier is called before the function is executed. Basically, it runs some checks to make sure everything is fine. In our case, we will make sure that this function is called by the owner only. To do this, we will use a popular contract from the OpenZeppelin Solidity library called *Ownable*. I will copy and paste it.

Don't worry if you don't understand everything in this contract. Just know that it makes sure our function will be called by the owner only.

- Create a Ownable.sol file in contracts

```
/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address public owner;

  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  function Ownable() public {
    owner = msg.sender;
  }


  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
}
```

- Import our Ownable contract in Questions and specify the function modifier for *setAnswersContractAddress*:

```
pragma solidity ^0.4.18;

import "./Ownable.sol";

contract AnswersInterface {
	function getAnswerUniverse() public view returns (uint);
}

contract Questions is Ownable{
	AnswersInterface answersContract;

	function setAnswersContractAddress(address _address) external onlyOwner{
		answersContract = AnswersInterface(_address);
	}

	function whatIsTheAnswerUniverse() public view returns (uint){
		uint answer = answersContract.getAnswerUniverse();
		return answer;
	}

}
```

Relaunch the ganache-cli command, and the truffle commands. Deploy our Answers and Questions contracts. By default, the contract's owner is the first account created by ganache-cli. So, we'll take another account:

`truffle(development)> account = web3.eth.accounts[3]`

Now, if we try to set the interface address from this account, we will get an error:

```
truffle(development)> Questions.setAnswersContractAddress('0x37eba1bb7d4c779474a4955437e524fbdbac0dc2', {from: account})
Error: VM Exception while processing transaction: revert
```

If you remove the object argument, or use the accounts[0] address in the from key, you will be able to set the address just fine.

That's it for interfaces and function modifiers. Have fun!!!