Files
openzeppelin-contracts/docs/modules/ROOT/pages/access-control.adoc
Francisco Giordano 7552af95e4 migrate content to format for new docs site
Squashed commit of the following:

commit fcf35eb806100de300bd9803ce3150dde1ecc424
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 17 17:16:04 2019 -0300

    remove all docsite dependency

commit eeaee9a9d43d70704f6ab17b5126ddbd52b93a50
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 17 17:15:23 2019 -0300

    update solidity-docgen

commit f021ff951829ea0c155186749819403c6b76e803
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 17 17:05:06 2019 -0300

    update docsite script for new setup

commit ff887699d381cfbbe3acf1f1c0de8e22b58480f3
Merge: c938aa1d 84f85a41
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 17 16:46:46 2019 -0300

    Merge branch 'master' into antora

commit c938aa1d9ed05ac83a34e2cebd8353f8331ad6d6
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue Jul 16 18:24:29 2019 -0300

    make component name shorter

commit 5bbd6931e02cbbd8864c82655ad0f390ceead5f3
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 10 20:16:17 2019 -0300

    add all info to docs templates

commit 39682c4515d7cf0f0368ed557f50d2709174208a
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 10 20:13:49 2019 -0300

    fix npm docsite script

commit 7ae46bd4a0437abf66150d54d05adf46e3de2cab
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 10 18:48:05 2019 -0300

    convert inline docs to asciidoc

commit cfdfd3dee4b4bf582fde22c8cb6e17a603d6e0c8
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 10 17:34:52 2019 -0300

    add missing contract names in readmes

commit 15b6a2f9bfb546cf1d3bf4f104278b118bf1b3f4
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 10 17:16:47 2019 -0300

    fix script path

commit 80d82b909f9460d1450d401f00b3f309da506b29
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 10 17:13:53 2019 -0300

    update version of solidity-docgen

commit a870b6c607b9c2d0012f8a60a4ed1a1c8b7e8ebd
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 10 17:03:53 2019 -0300

    add nav generation of api ref

commit 069cff4a25b83752650b54b86d85608c2f547e5e
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Wed Jul 10 16:32:14 2019 -0300

    initial migration to asciidoc and new docgen version

commit 55216eed0a6551da913c8d1da4b2a0d0d3faa1a8
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue Jun 25 20:39:35 2019 -0300

    add basic api doc example

commit 0cbe50ce2173b6d1d9a698329d91220f58822a53
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue Jun 25 19:31:31 2019 -0300

    add sidebars

commit 256fc942845307258ac9dc25aace48117fa10f79
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue Jun 25 15:22:38 2019 -0300

    add page titles

commit f4d0effa70e1fc0662729863e8ee72a8821bc458
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue Jun 25 15:19:41 2019 -0300

    add contracts index file

commit b73b06359979f7d933df7f2b283c50cb1c31b2a0
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue Jun 25 15:14:52 2019 -0300

    fix header levels

commit fb57d9b820f09a1b7c04eed1a205be0e45866cac
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue Jun 25 15:11:47 2019 -0300

    switch format to preferred asciidoctor format

commit 032181d8804137332c71534753929d080a31a71f
Author: Francisco Giordano <frangio.1@gmail.com>
Date:   Tue Jun 25 15:05:38 2019 -0300

    initialize antora component and convert docs to asciidoc
2019-07-17 17:16:47 -03:00

109 lines
7.1 KiB
Plaintext

= Access Control
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 may govern who can mint tokens, vote on proposals, freeze transfers, and many others. It is therefore critical to understand how you implement it, lest someone else https://blog.zeppelin.solutions/on-the-parity-wallet-multisig-hack-405a8c12e8f7[steals your whole system].
[[ownership-and-ownable]]
== Ownership and `Ownable`
The most common and basic form of access control is the concept of _ownership_: there's an account that is the `owner` of a contract and can do administrative tasks on it. This approach is perfectly reasonable for contracts that have a single administrative user.
OpenZeppelin provides link:api/ownership#ownable[`Ownable`] for implementing ownership in your contracts.
[source,solidity]
----
pragma solidity ^0.5.0;
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()!
}
}
----
By default, the link:api/ownership#Ownable.owner()[`owner`] of an `Ownable` contract is the account that deployed it, which is usually exactly what you want.
Ownable also lets you: - link:api/ownership#Ownable.transferOwnership(address)[`transferOwnership`] from the owner account to a new one - link:api/ownership#Ownable.renounceOwnership()[`renounceOwnership`] for the owner to lose this administrative privilege, a common pattern after an initial stage with centralized administration is over - *⚠ Warning! ⚠* Removing the owner altogether will mean that administrative tasks that are protected by `onlyOwner` will no longer be callable!
Note that *a contract can also be the owner of another one*! This opens the door to using, for example, a https://github.com/gnosis/MultiSigWallet[Gnosis Multisig] or https://safe.gnosis.io[Gnosis Safe], an https://aragon.org[Aragon DAO], an https://www.uport.me[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 regular Ethereum account (Externally Owned Account, or EOA) as the owner, you could use a 2-of-3 multisig run by your project leads, for example. Prominent projects in the space, such as https://makerdao.com[MakerDAO], use systems similar to this one.
[[role-based-access-control]]
== Role-Based Access Control
While the simplicity of _ownership_ can be useful for simple systems or quick prototyping, different levels of authorization are often needed. An account may be able to ban users from a system, but not create new tokens. _Role-Based Access Control (RBAC)_ offers flexibility in this regard.
In essence, we will be defining multiple _roles_, each allowed to perform different sets of actions. Instead of `onlyOwner` everywhere you will use, for example, `onlyAdminRole` in some places, and `onlyModeratorRole` in others. Separately you will be able to define rules for how accounts can be assignned a role, transfer it, and more.
Most of software development uses access control systems that are role-based: some users are regular users, some may be supervisors or managers, and a few will often have administrative privileges.
[[using-roles]]
=== Using `Roles`
OpenZeppelin provides link:api/access#roles[`Roles`] for implementing role-based access control. Its usage is straightforward: for each role that you want to define, you'll store a variable of type `Role`, which will hold the list of accounts with that role.
Here's an simple example of using `Roles` in an link:tokens#erc20[`ERC20` token]: we'll define two roles, `namers` and `minters`, that will be able to change the name of the token contract, and mint new tokens, respectively.
[source,solidity]
----
pragma solidity ^0.5.0;
import "openzeppelin-solidity/contracts/access/Roles.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
contract MyToken is ERC20, ERC20Detailed {
using Roles for Roles.Role;
Roles.Role private _minters;
Roles.Role private _namers;
constructor(address[] memory minters, address[] memory namers)
DetailedERC20("MyToken", "MTKN", 18)
public
{
for (uint256 i = 0; i < minters.length; ++i) {
_minters.add(minters[i]);
}
for (uint256 i = 0; i < namers.length; ++i) {
_namers.add(namers[i]);
}
}
function mint(address to, uint256 amount) public {
// Only minters can mint
require(minters.has(msg.sender), "DOES_NOT_HAVE_MINTER_ROLE");
_mint(to, amount);
}
function rename(string memory name, string memory symbol) public {
// Only namers can change the name and symbol
require(namers.has(msg.sender), "DOES_NOT_HAVE_NAMER_ROLE");
name = name;
symbol = symbol;
}
}
----
So clean! By splitting concerns this way, we can define more granular levels of permission, which was lacking in the _ownership_ approach to access control. Note that an account may have more than one role, if desired.
OpenZeppelin uses `Roles` extensively with predefined contracts that encode rules for each specific role. A few examples are: link:api/token/ERC20#erc20mintable[`ERC20Mintable`] which uses the link:api/access#minterrole[`MinterRole`] to determine who can mint tokens, and link:api/crowdsale#whitelistcrowdsale[`WhitelistCrowdsale`] which uses both link:api/access#whitelistadminrole[`WhitelistAdminRole`] and link:api/access#whitelistedrole[`WhitelistedRole`] to create a set of accounts that can purchase tokens.
This flexibility allows for interesting setups: for example, a link:api/crowdsale#mintedcrowdsale[`MintedCrowdsale`] expects to be given the `MinterRole` of an `ERC20Mintable` in order to work, but the token contract could also extend link:api/token/ERC20#erc20pausable[`ERC20Pausable`] and assign the link:api/access#pauserrole[`PauserRole`] to a DAO that serves as a contingency mechanism in case a vulnerability is discovered in the contract code. Limiting what each component of a system is able to do is known as the https://en.wikipedia.org/wiki/Principle_of_least_privilege[principle of least privilege], and is a good security practice.
[[usage-in-openzeppelin]]
== Usage in OpenZeppelin
You'll notice that none of the OpenZeppelin contracts use `Ownable`. `Roles` is a prefferred solution, because it provides the user of the library with enough flexibility to adapt the provided contracts to their needs.
There are some cases, though, where there's a direct relationship between contracts. For example, link:api/crowdsale#refundablecrowdsale[`RefundableCrowdsale`] deploys a link:api/payment#refundescrow[`RefundEscrow`] on construction, to hold its funds. For those cases, we'll use link:api/ownership#secondary[`Secondary`] to create a _secondary_ contract that allows a _primary_ contract to manage it. You could also think of these as _auxiliary_ contracts.