You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
5.3 KiB
105 lines
5.3 KiB
6 years ago
|
---
|
||
6 years ago
|
id: access-control
|
||
|
title: Access Control
|
||
6 years ago
|
---
|
||
|
|
||
|
Access control—that is, "who is allowed to do this thing"—is incredibly important in the world of smart contracts. The access control of your contract governs who can mint tokens, who can vote on proposals, who can [`selfdestruct()`](https://blog.zeppelin.solutions/on-the-parity-wallet-multisig-hack-405a8c12e8f7) the contract, and more, so it's very important to understand how you implement it.
|
||
|
|
||
|
## Ownership & Ownable.sol
|
||
|
|
||
|
The most common and basic form of access control is the concept of _ownership_: there's one account that is the `owner` and can do administrative tasks on contracts. This approach is perfectly reasonable for contracts that only have a single administrative user.
|
||
|
|
||
6 years ago
|
OpenZeppelin provides [`Ownable`](api/ownership#ownable) for implementing ownership in your contracts.
|
||
6 years ago
|
|
||
|
```solidity
|
||
|
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
|
||
|
|
||
|
contract MyContract is Ownable {
|
||
|
|
||
|
function normalThing()
|
||
|
public
|
||
|
{
|
||
|
// anyone can call this normalThing()
|
||
|
}
|
||
|
|
||
|
function specialThing()
|
||
|
public
|
||
|
onlyOwner
|
||
|
{
|
||
|
// only the owner can call specialThing()!
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
6 years ago
|
By default, the [`owner`](api/ownership#Ownable.owner()) of an `Ownable` contract is the `msg.sender` of the contract creation transaction, which is usually exactly what you want.
|
||
6 years ago
|
|
||
|
Ownable also lets you:
|
||
6 years ago
|
+ [`transferOwnership`](api/ownership#Ownable.transferOwnership(address)) to transfer ownership from one account to another
|
||
|
+ [`renounceOwnership`](api/ownership#Ownable.renounceOwnership()) to remove the owner altogether, useful for decentralizing control of your contract. **⚠ Warning!** Removing the owner altogether will mean that administrative tasks that are protected by `onlyOwner` will no longer be callable!
|
||
6 years ago
|
|
||
|
|
||
|
Note that any contract that supports sending transactions can also be the owner of a contract; the only requirement is that the owner has an Ethereum address, so it could be a Gnosis Multisig or Gnosis Safe, an Aragon DAO, an ERC725/uPort identity contract, or a totally custom contract that _you_ create.
|
||
|
|
||
|
In this way you can use _composability_ to add additional layers of access control complexity to your contracts. Instead of having a single Ethereum Off-Chain Account (EOA) as the owner, you can replace them with a 2/3 multisig run by your project leads, for example.
|
||
|
|
||
|
### Examples in OpenZeppelin
|
||
|
|
||
6 years ago
|
You'll notice that none of the OpenZeppelin contracts use `Ownable`, though! This is because there are more flexible ways of providing access control that are more in-line with our reusable contract philosophy. For most contracts, We'll use `Roles` to govern who can do what. There are some cases, though—like with [`Escrow`](localhost:3000/api/payment#escrow)—where there's a direct relationship between contracts. In those cases, we'll use [`Secondary`](api/ownership#secondary) to create a "secondary" contract that allows a "primary" contract to manage it.
|
||
6 years ago
|
|
||
|
Let's learn about Role-Based Access Control!
|
||
|
|
||
6 years ago
|
## Roles & Role-Based Access Control
|
||
6 years ago
|
|
||
|
An alternative to single-concern `Ownable` is role based access control (RBAC), which, instead of keeping track of a single entity with "admin" level privileges, keeps track of multiple different entities with a variety of roles that inform the contract about what they can do.
|
||
|
|
||
6 years ago
|
For example, a [`MintableToken`](api/token/ERC20#erc20mintable) could have a `minter` role that decides who can mint tokens (which could be assigned to a [`Crowdsale`](api/crowdsale#crowdsale)). It could also have a `namer` role that allows changing the name or symbol of the token (for whatever reason). RBAC gives you much more flexibility over who can do what and is generally recommended for applications that need more configurability. If you're experienced with web development, the vast majority of access control systems are role-based: some users are normal users, some are moderators, and some can be company employee admins.
|
||
6 years ago
|
|
||
6 years ago
|
OpenZeppelin provides [`Roles`](api/access#roles) for implementing role-based access control.
|
||
6 years ago
|
|
||
|
Here's an example of using `Roles` in our token example above, we'll use it to implement a token that can be minted by `Minters` and renamed by `Namers`:
|
||
|
|
||
|
```solidity
|
||
|
import "openzeppelin-solidity/contracts/access/Roles.sol";
|
||
|
|
||
|
contract MyToken is DetailedERC20, StandardToken {
|
||
|
using Roles for Roles.Role;
|
||
|
|
||
|
Roles.Role private minters;
|
||
|
Roles.Role private namers;
|
||
|
|
||
|
constructor(
|
||
|
string name,
|
||
|
string symbol,
|
||
|
uint8 decimals,
|
||
|
address[] minters,
|
||
|
address[] namers,
|
||
|
)
|
||
|
DetailedERC20(name, symbol, decimals)
|
||
|
Standardtoken()
|
||
|
public
|
||
|
{
|
||
|
namers.addMany(namers);
|
||
|
minters.addMany(minters);
|
||
|
}
|
||
|
|
||
|
function mint(address to, uint256 amount)
|
||
|
public
|
||
|
{
|
||
|
// only allow minters to mint
|
||
|
require(minters.has(msg.sender), "DOES_NOT_HAVE_MINTER_ROLE");
|
||
|
_mint(to, amount);
|
||
|
}
|
||
|
|
||
|
function rename(string name, string symbol)
|
||
|
public
|
||
|
{
|
||
|
// only allow namers to name
|
||
|
require(namers.has(msg.sender), "DOES_NOT_HAVE_NAMER_ROLE");
|
||
|
name = name;
|
||
|
symbol = symbol;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
So clean! You'll notice that the role associations are always the last arguments in the constructor; this is a good pattern to follow to keep your code more organized.
|