Merge branch 'master' into solc-0.7
This commit is contained in:
@ -185,3 +185,37 @@ for (let i = 0; i < minterCount; ++i) {
|
||||
members.push(await myToken.getRoleMember(MINTER_ROLE, i));
|
||||
}
|
||||
```
|
||||
|
||||
== Delayed operation
|
||||
|
||||
Access control is essential to prevent unauthorized access to critical functions. These functions may be used to mint tokens, freeze transfers or perform an upgrade that completely changes the smart contract logic. While xref:api:access.adoc#Ownable[`Ownable`] and xref:api:access.adoc#AccessControl[`AccessControl`] can prevent unauthorized access, they do not address the issue of a misbehaving administrator attacking their own system to the prejudice of their users.
|
||||
|
||||
This is the issue the xref:api:access.adoc#TimelockController[`TimelockControler`] is addressing.
|
||||
|
||||
The xref:api:access.adoc#TimelockController[`TimelockControler`] is a proxy that is governed by proposers and executors. When set as the owner/admin/controller of a smart contract, it ensures that whichever maintenance operation is ordered by the proposers is subject to a delay. This delay protects the users of the smart contract by giving them time to review the maintenance operation and exit the system if they consider it is in their best interest to do so.
|
||||
|
||||
=== Using `TimelockControler`
|
||||
|
||||
By default, the address that deployed the xref:api:access.adoc#TimelockController[`TimelockControler`] gets administration privileges over the timelock. This role grants the right to assign proposers, executors, and other administrators.
|
||||
|
||||
The first step in configuring the xref:api:access.adoc#TimelockController[`TimelockControler`] is to assign at least one proposer and one executor. These can be assigned during construction or later by anyone with the administrator role. These roles are not exclusive, meaning an account can have both roles.
|
||||
|
||||
Roles are managed using the xref:api:access.adoc#AccessControl[`AccessControl`] interface and the `bytes32` values for each role are accessible through the `ADMIN_ROLE`, `PROPOSER_ROLE` and `EXECUTOR_ROLE` constants.
|
||||
|
||||
There is an additional feature built on top of `AccessControl`: giving the proposer or executor role to `address(0)` opens access to anyone. This feature, while potentially useful for testing and in some cases for the executor role, is dangerous and should be used with caution.
|
||||
|
||||
At this point, with both a proposer and an executor assigned, the timelock can perform operations.
|
||||
|
||||
An optional next step is for the deployer to renounce its administrative privileges and leave the timelock self-administered. If the deployer decides to do so, all further maintenance, including assigning new proposers/schedulers or changing the timelock duration will have to follow the timelock workflow. This links the governance of the timelock to the governance of contracts attached to the timelock, and enforce a delay on timelock maintenance operations.
|
||||
|
||||
WARNING: If the deployer renounces administrative rights in favour of timelock itself, assigning new proposers or executors will require a timelocked operation. This means that if the accounts in charge of any of these two roles become unavailable, then the entire contract (and any contract it controls) becomes locked indefinitely.
|
||||
|
||||
With both the proposer and executor roles assigned and the timelock in charge of its own administration, you can now transfer the ownership/control of any contract to the timelock.
|
||||
|
||||
TIP: A recommended configuration is to grant both roles to a secure governance contract such as a DAO or a multisig, and to additionally grant the executor role to a few EOAs held by people in charge of helping with the maintenance operations. These wallets cannot take over control of the timelock but they can help smoothen the workflow.
|
||||
|
||||
=== Minimum delay
|
||||
|
||||
Operations executed by the xref:api:access.adoc#TimelockController[`TimelockControler`] are not subject to a fixed delay but rather a minimum delay. Some major updates might call for a longer delay. For example, if a delay of just a few days might be sufficient for users to audit a minting operation, it makes sense to use a delay of a few weeks, or even a few months, when scheduling a smart contract upgrade.
|
||||
|
||||
The minimum delay (accessible through the xref:api:access.adoc#TimelockController-getMinDelay--[`getMinDelay`] method) can be updated by calling the xref:api:access.adoc#TimelockController-updateDelay-uint256-[`updateDelay`] function. Bear in mind that access to this function is only accessible by the timelock itself, meaning this maintenance operation has to go through the timelock itself.
|
||||
|
||||
@ -45,7 +45,7 @@ contract GameItems is ERC1155 {
|
||||
uint256 public constant SWORD = 3;
|
||||
uint256 public constant SHIELD = 4;
|
||||
|
||||
constructor() ERC1155("https://game.example/api/item/{1}.json") {
|
||||
constructor() ERC1155("https://game.example/api/item/{id}.json") {
|
||||
_mint(msg.sender, GOLD, 10**18, "");
|
||||
_mint(msg.sender, SILVER, 10**27, "");
|
||||
_mint(msg.sender, THORS_HAMMER, 1, "");
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
* Flexible xref:access-control.adoc[role-based permissioning] scheme.
|
||||
* Reusable xref:utilities.adoc[Solidity components] to build custom contracts and complex decentralized systems.
|
||||
* First-class integration with the xref:gsn.adoc[Gas Station Network] for systems with no gas fees!
|
||||
* Audited by leading security firms (_last full audit on v2.0.0_).
|
||||
* https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/audit[Audited] by leading security firms (_last full audit on v2.0.0_).
|
||||
|
||||
== Overview
|
||||
|
||||
|
||||
71
docs/modules/ROOT/pages/upgradeable.adoc
Normal file
71
docs/modules/ROOT/pages/upgradeable.adoc
Normal file
@ -0,0 +1,71 @@
|
||||
= Using with Upgrades
|
||||
|
||||
If your contract is going to be deployed with upgradeability, such as using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins], you will need to use the Upgrade Safe variant of OpenZeppelin Contracts.
|
||||
|
||||
This variant is available as a separate package called `@openzeppelin/contracts-upgradeable`, which is hosted in the repository https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable[OpenZeppelin/openzeppelin-contracts-upgradeable].
|
||||
|
||||
It follows all of the rules for xref:upgrades-plugins::writing-upgradeable.adoc[Writing Upgradeable Contracts]: constructors are replaced by initializer functions, state variables are initialized in initializer functions, and we additionally check for storage incompatibilities across minor versions.
|
||||
|
||||
== Overview
|
||||
|
||||
=== Installation
|
||||
|
||||
```console
|
||||
$ npm install @openzeppelin/contracts-upgradeable
|
||||
```
|
||||
|
||||
=== Usage
|
||||
|
||||
The package replicates the structure of the main OpenZeppelin Contracts package, but every file and contract has the suffix `Upgradeable`.
|
||||
|
||||
```diff
|
||||
-import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
+import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
|
||||
|
||||
-contract MyCollectible is ERC721 {
|
||||
+contract MyCollectible is ERC721Upgradeable {
|
||||
```
|
||||
|
||||
Constructors are replaced by internal initializer functions following the naming convention `+__{ContractName}_init+`. Since these are internal, you must always define your own public initializer function and call the parent initializer of the contract you extend.
|
||||
|
||||
```diff
|
||||
- constructor() ERC721("MyCollectible", "MCO") public {
|
||||
+ function initialize() initializer public {
|
||||
+ __ERC721_init("MyCollectible", "MCO");
|
||||
}
|
||||
```
|
||||
|
||||
CAUTION: Use with multiple inheritance requires special attention. See the section below titled <<multiple-inheritance>>.
|
||||
|
||||
Once this contract is set up and compiled, you can deploy it using the xref:upgrades-plugins::index.adoc[Upgrades Plugins]. The following snippet shows an example deployment script using Hardhat.
|
||||
|
||||
```js
|
||||
// scripts/deploy-my-collectible.js
|
||||
const { ethers, upgrades } = require("hardhat");
|
||||
|
||||
async function main() {
|
||||
const MyCollectible = await ethers.getContractFactory("MyCollectible");
|
||||
|
||||
const mc = await upgrades.deployProxy(MyCollectible);
|
||||
|
||||
await mc.deployed();
|
||||
console.log("MyCollectible deployed to:", mc.address);
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
== Further Notes
|
||||
|
||||
[[multiple-inheritance]]
|
||||
=== Multiple Inheritance
|
||||
|
||||
Initializer functions are not linearized by the compiler like constructors. Because of this, each `+__{ContractName}_init+` function embeds the linearized calls to all parent initializers. As a consequence, calling two of these `init` functions can potentially initialize the same contract twice.
|
||||
|
||||
The function `+__{ContractName}_init_unchained+` found in every contract is the initializer function minus the calls to parent initializers, and can be used to avoid the double initialization problem, but doing this manually is not recommended. We hope to be able to implement safety checks for this in future versions of the Upgrades Plugins.
|
||||
|
||||
=== Storage Gaps
|
||||
|
||||
You may notice that every contract includes a state variable named `+__gap+`. This is empty reserved space in storage that is put in place in Upgrade Safe contracts. It allows us to freely add new state variables in the future without compromising the storage compatibility with existing deployments.
|
||||
|
||||
It isn't safe to simply add a state variable because it "shifts down" all of the state variables below in the inheritance chain. This makes the storage layouts incompatible, as explained in xref:upgrades-plugins::writing-upgradeable.adoc#modifying-your-contracts[Writing Upgradeable Contracts]. The size of the `+__gap+` array is calculated so that the amount of storage used by a contract always adds up to the same number (in this case 50 storage slots).
|
||||
Reference in New Issue
Block a user