All you need to know about openzeppelin access control
Published: 2023-07-27 04:57:34

## what is access control
![Alt access control](https://github.com/coffiasd/images/blob/6b8faa901198b07cf99a106518dc14842cc4fe1f/030726.png?raw=true)

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
```solidity
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()!
    }
}
```

let's create two user for our test.
- owner address
- arbitrary address

```solidity
    address owner = address(0x100);
    address arbitrary = address(0x101);
```

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.
```solidity
//let's set address owner to msg.sender.
vm.prank(owner);

//create the contract.
myContract = new MyContract();
```

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:
```solidity
//use arbitrary address invoke specialThing() function.
vm.prank(arbitrary);
vm.expectRevert("Ownable: caller is not the owner");
myContract.specialThing();
```

Finally,we use our owner who master the contract invoke the `specialThing` function.As you see the owne succeed.
```solidity
//switch to owner.
vm.prank(owner);
myContract.specialThing();
```

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
```solidity
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);
    }
}
```

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:
```solidity
// Create a new role identifier for the minter role
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
```

Firstly,we use `owner` address as our minter to create our access control contract.
```solidity
 myToken = new MyToken2(owner);
```

And then we use the arbitrary user to mint some ERC20 token:
```solidity
//use arbitrary address invoke mint() function.
vm.prank(arbitrary);
vm.expectRevert("Caller is not a minter");
myToken.mint(address(this), 1);
```
the above invoke would be revert because of arbitrary don't hold the minter role.

```solidity
//switch to owner.
vm.prank(owner);
myToken.mint(address(this), 1);
```
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:
```solidity
vm.prank(owner);
myToken.grantRole(keccak256("MINTER_ROLE"), arbitrary);

vm.prank(arbitrary);
myToken.mint(address(this), 1);
```
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:
```solidity
vm.prank(arbitrary);
vm.expectRevert();
myToken.grantRole(keccak256("MINTER_ROLE"), address(0x1001));
```

As the owner we also have the right to revoke role we grant before:
```solidity
vm.prank(owner);
myToken.revokeRole(keccak256("MINTER_ROLE"), arbitrary);

vm.prank(arbitrary);
vm.expectRevert("Caller is not a minter");
myToken.mint(address(this), 1);
```
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