Understanding Ownership and Role-based Access with Solidity and OpenZeppelin

Ngenge Senior
The Startup
Published in
5 min readMay 19, 2019
Photo by Tomas Sobek on Unsplash

I started off getting an understanding of the whole thing about smart contracts and Solidity two months ago. This will be my first post on Smart contracts and the same will be published on my blog, Threaded Coder .

What is the Ownership and Role thing all about?

Let us say Mr. A owns a school, we want that when students pay fees, the fees go directly into his account. We also have students and teachers. But only students get to pay fees while only teachers can grade students. So we have the following scenario.

  • Mr. A is the Owner.
  • There are students who can pay fees(Have a Student Role).
  • Teachers who can grade students(Teacher Role).
  • Mr. A can choose to close his school because of one reason or the other.

Scenarios like these come about most at times in smart contracts development where you will want to allocate roles to particular addresses or contracts. No contract should be able to execute a particular function if it is not supposed to do so.

In effect, it is a way of designing secure smart contracts to avoid unnecessary behavior. This is a very critical aspect that needs thorough thinking when designing not just smart contracts but programming in general.

Open Zeppelin to the Rescue.

OpenZeppelin is a library developed and maintained by Zeppelin for creating secure smart contracts for Ethereum and other blockchains. It is designed with contract security as its main concern.

So we will see how to model our Class example above with roles using OpenZeppelin library.

Creating a project and Installing OpenZeppelin

We, first of all, have to install truffle if it is not, then create our project with the following commands;

$ npm install -g truffle
$ mkdir class_project && cd class_project
$ truffle init

We then install OpenZeppelin to our current project using npm with the following commands;

$ npm init -y
$ npm install --save-exact openzeppelin-solidity

After this, you should have the library in the node_modules directory of your project with the following directory structure.

OpenZeppelin library

Thankfully, Truffle can import contracts in node_modules directory as it understands node_modules. Here is the link to the Roles library. It has three methods; add, for giving account access to a role, remove, for removing an account’s access to the role and, has for checking if an account has a particular role. We will use these methods for adding the Teacher and Student Roles in our smart contract.

Here is a link to the Ownable.sol . It has one private variable _owner and methods to transfer ownership from one address to another. The owner of the contract will be the address that deploys the contract, that is the first address. So we could define contract to extend from Ownable thus;

contract ClassContract is Ownable {// Rest of contract code}

OK, at this point, let us define how our contract operates as per the Teacher and Student Roles.

Constraints of our Contract to ensure security

  • Deploying address is the owner of the school
  • Only the owner can give teacher and student roles(can admit teachers and students).
  • Only students can pay fees.
  • Only teachers can grade students.
  • Only the owner can choose to terminate the school; At this point, we have a contract as such;

Let us develop our smart contract

  • First, we import Ownable.sol and Roles.sol from the various packages in our contract file as shown below, we then inherit from Ownable.sol and we declare that we want to use the Roles library in our contract;
  • We have two roles, so we define two variables to store our teacher and student roles. With these, our contract should be as shown below.

Notice that we added two mappings to keep track of student grades and student fees.

Next, let us create two methods that each take an array of addresses and adds the addresses to the teacher Roles and student Roles. We also enforce that only the owner (principal of our virtual class) can call these methods to add roles.

The onlyOwner modifier comes from the Ownable , declaring that only our contract owner can call the functions. We use the add function from the Roles library to assign student and teacher Roles. You can check the signature of add in the Roles.sol file as it takes Role parameter and address as the second parameter.

function add(Role storage role, address account) internal {
// Rest of function body
}

Well, you might be wondering why the calls students.add(students[i]) and teachers.add(teachers[i]) , are not taking two parameters.Note that Roles is a library (reason why we declare using Roles.Role for Role) but the rule is that all calls to library functions will receive the object they are called on as their first parameter.

Let us see how we enforce the use of roles by creating functions that will only be executed successfully if a certain account has access to a role using the Roles library’s has method.

  • payFees will ensure that only students can pay fees.
  • gradeStudent ensures that only a teacher can grade a student.
  • We also add a little condition that students can only pay a one time fee of at least 4 ether.

Roles

The payFees function adds a require to ensure that the caller of this function has access to the student role. The fees are then transferred to the address of the contract owner which we have access to from the public method in Ownable, owner() which returns the owner.

For new versions of Solidity, only a payable address can be transferred ether, but _owner from Ownable is not payable. I faced this issue with my contract crashing on compiling. The workaround is to cast the address to address(uint160).

With this, you will come to the understanding that we have enforced security in the contract in two ways.

  • Through ownership using Ownable
  • Restricting access to functions using Roles.

Let us set up our tests, add some teacher and student roles and run our tests.

I won’t take time explaining how writing tests work but it should be obvious if you understand some level of smart contracts tests with Solidity and JavaScript tests. Basically with the test, we set up teacher accounts and student accounts and test the various functions.

Here is a link below to the complete code on Github.

Thank you and happy coding!

--

--