DEV Community

Ayden
Ayden

Posted on

All you need to know about openzeppelin access control

what is access control

Alt access control

Basiclly,access control means "who is allowed to do this thing".It's quite important for smart contract to specify a particular address who can totally control the whole system.Therefor it's critical to fully understand how to use access control before using it in your project or just copy some example code from somewhere.
In openzeppelin there are mainly two ways to implementing access control.

  • Single onlyOwner role
  • Role-Based Access Control (RBAC)

Let's dive into how to master this 2 ways.

master how to use it by practice

OnlyOwner

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

contract MyContract is Ownable {
    function normalThing() public {
        // anyone can call this normalThing()
    }

    function specialThing() public onlyOwner {
        // only the owner can call specialThing()!
    }
}
Enter fullscreen mode Exit fullscreen mode

let's create two user for our test.

  • owner address
  • arbitrary address
    address owner = address(0x100);
    address arbitrary = address(0x101);
Enter fullscreen mode Exit fullscreen mode

and the we use owner address to create the smart contract,it's quite simple you don't even need to pass any parameters.openzeppelin Ownable would set msg.sender as it's owner as default.we use foundry for testing,if you're not familiar with foundry,go and learn it first before proceeding further.

Firstly,we use owner address create our smart contract above in foundry test contract setUp function.

//let's set address owner to msg.sender.
vm.prank(owner);

//create the contract.
myContract = new MyContract();
Enter fullscreen mode Exit fullscreen mode

And then we use the arbitrary address to invoke the specialThing function which is protected by onlyOwner modifier.As expect the invoke revert because of access control.Here goes the code:

//use arbitrary address invoke specialThing() function.
vm.prank(arbitrary);
vm.expectRevert("Ownable: caller is not the owner");
myContract.specialThing();
Enter fullscreen mode Exit fullscreen mode

Finally,we use our owner who master the contract invoke the specialThing function.As you see the owne succeed.

//switch to owner.
vm.prank(owner);
myContract.specialThing();
Enter fullscreen mode Exit fullscreen mode

If you want the whole example codes go for:https://gist.github.com/coffiasd/84552b5a33845fa567bfc3aa5204d460
If you have any questions, you can also reach me through the contact information below.

Role-Based Access Control

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken2 is ERC20, AccessControl {
    // Create a new role identifier for the minter role
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    constructor(address minter) ERC20("MyToken", "TKN") {
        _grantRole(DEFAULT_ADMIN_ROLE, minter);
        // Grant the minter role to a specified account
        _grantRole(MINTER_ROLE, minter);
    }

    function mint(address to, uint256 amount) public {
        // Check that the calling account has the minter role
        require(hasRole(MINTER_ROLE, msg.sender), "Caller is not a minter");
        _mint(to, amount);
    }
}
Enter fullscreen mode Exit fullscreen mode

We can create whatever role we want in Role-Based Access Control (RBAC) contract.Let's say we want create a minter role who can mint some ERC20 token.We can use a special constant bytes32 as the name of the role like this:

// Create a new role identifier for the minter role
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
Enter fullscreen mode Exit fullscreen mode

Firstly,we use owner address as our minter to create our access control contract.

 myToken = new MyToken2(owner);
Enter fullscreen mode Exit fullscreen mode

And then we use the arbitrary user to mint some ERC20 token:

//use arbitrary address invoke mint() function.
vm.prank(arbitrary);
vm.expectRevert("Caller is not a minter");
myToken.mint(address(this), 1);
Enter fullscreen mode Exit fullscreen mode

the above invoke would be revert because of arbitrary don't hold the minter role.

//switch to owner.
vm.prank(owner);
myToken.mint(address(this), 1);
Enter fullscreen mode Exit fullscreen mode

If we switch msg.sender to owner the call would successed.

What's more? we can use owner address to grant a minter role whoever we want.Let's say we grant the minter role to the arbitrary address:

vm.prank(owner);
myToken.grantRole(keccak256("MINTER_ROLE"), arbitrary);

vm.prank(arbitrary);
myToken.mint(address(this), 1);
Enter fullscreen mode Exit fullscreen mode

After invoke the grantRole function the arbitrary has the right to mint token.

At the same time,arbitrary address don't has the right to grant role to another address:

vm.prank(arbitrary);
vm.expectRevert();
myToken.grantRole(keccak256("MINTER_ROLE"), address(0x1001));
Enter fullscreen mode Exit fullscreen mode

As the owner we also have the right to revoke role we grant before:

vm.prank(owner);
myToken.revokeRole(keccak256("MINTER_ROLE"), arbitrary);

vm.prank(arbitrary);
vm.expectRevert("Caller is not a minter");
myToken.mint(address(this), 1);
Enter fullscreen mode Exit fullscreen mode

After we invoke role of arbitrary,he can't mint ERC20 token anymore.

If you want the whole example codes go for:https://gist.github.com/coffiasd/340241d63980dc9d423e4ece2f9b20db
If you have any questions, you can also reach me through the contact information below.

Origin:https://blog.coffiasd.cn/03-07-26.html

let's connect

Twitter:https://twitter.com/coffiasse
Github:https://github.com/coffiasd
TG:@coffiasd

Top comments (0)