Merge branch 'master' into release-v3.0.0

This commit is contained in:
Nicolás Venturo
2020-04-03 16:22:25 -03:00
94 changed files with 4995 additions and 3467 deletions

View File

@ -11,7 +11,7 @@ OpenZeppelin provides xref:api:access.adoc#Ownable[`Ownable`] for implementing o
[source,solidity]
----
pragma solidity ^0.5.0;
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/access/Ownable.sol";
@ -69,7 +69,7 @@ contract MyToken is ERC20, AccessControl {
constructor(address minter) public {
// Grant the minter role to a specified account
_grantRole(MINTER_ROLE, minter);
_setupRole(MINTER_ROLE, minter);
}
function mint(address to, uint256 amount) public {
@ -98,8 +98,8 @@ contract MyToken is ERC20, AccessControl {
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
constructor(address minter, address burner) public {
_grantRole(MINTER_ROLE, minter);
_grantRole(BURNER_ROLE, burner);
_setupRole(MINTER_ROLE, minter);
_setupRole(BURNER_ROLE, burner);
}
function mint(address to, uint256 amount) public {
@ -119,11 +119,11 @@ So clean! By splitting concerns this way, more granular levels of permission may
[[granting-and-revoking]]
=== Granting and Revoking Roles
The ERC20 token example above uses `\_grantRole`, an `internal` function that is useful when programmatically asigning roles (such as during construction). But what if we later want to grant the 'minter' role to additional accounts?
The ERC20 token example above uses `\_setupRole`, an `internal` function that is useful when programmatically asigning roles (such as during construction). But what if we later want to grant the 'minter' role to additional accounts?
By default, **accounts with a role cannot grant it or revoke it from other accounts**: all having a role does is making the `hasRole` check pass. To grant and revoke roles dynamically, you will need help from the _role's admin_.
Every role has an associated admin role, which grants permission to call the `grantRole` and `revokeRole` `external` functions. A role can be granted or revoked by using these if the calling account has the corresponding admin role. Multiple roles may have the same admin role to make management easier. A role's admin can even be the same role itself, which would cause accounts with that role to be able to also grant and revoke it.
Every role has an associated admin role, which grants permission to call the `grantRole` and `revokeRole` functions. A role can be granted or revoked by using these if the calling account has the corresponding admin role. Multiple roles may have the same admin role to make management easier. A role's admin can even be the same role itself, which would cause accounts with that role to be able to also grant and revoke it.
This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also provides an easy way to manage simpler applications. `AccessControl` includes a special role, called `DEFAULT_ADMIN_ROLE`, which acts as the **default admin role for all roles**. An account with this role will be able to manage any other role, unless `\_setRoleAdmin` is used to select a new admin role.
@ -140,10 +140,10 @@ contract MyToken is ERC20, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
constructor() public {
constructor() ERC20("MyToken", "TKN") public {
// Grant the contract deployer the default admin role: it will be able
// to grant and revoke any roles
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
}
function mint(address to, uint256 amount) public {

View File

@ -55,7 +55,7 @@ As we can see, `_mint` makes it super easy to do this correctly.
[[modularizing-the-mechanism]]
== Modularizing the Mechanism
There is one supply mechanism already included in Contracts: xref:api:token/ERC20.adoc#ERC20Mintable[`ERC20Mintable`]. This is a generic mechanism in which a set of accounts is assigned the `minter` role, granting them the permission to call a xref:api:token/ERC20.adoc#ERC20Mintable-mint-address-uint256-[`mint`] function, an external version of `_mint`.
There is one supply mechanism already included in Contracts: `ERC20DeployReady`. This is a generic mechanism in which a set of accounts is assigned the `minter` role, granting them the permission to call a `mint` function, an external version of `_mint`.
This can be used for centralized minting, where an externally owned account (i.e. someone with a pair of cryptographic keys) decides how much supply to create and to whom. There are very legitimate use cases for this mechanism, such as https://medium.com/reserve-currency/why-another-stablecoin-866f774afede#3aea[traditional asset-backed stablecoins].
@ -64,9 +64,9 @@ The accounts with the minter role don't need to be externally owned, though, and
[source,solidity]
----
contract MinerRewardMinter {
ERC20Mintable _token;
ERC20DeployReady _token;
constructor(ERC20Mintable token) public {
constructor(ERC20DeployReady token) public {
_token = token;
}
@ -76,7 +76,9 @@ contract MinerRewardMinter {
}
----
This contract, when initialized with an `ERC20Mintable` instance, will result in exactly the same behavior implemented in the previous section. What is interesting about using `ERC20Mintable` is that we can easily combine multiple supply mechanisms by assigning the role to multiple contracts, and moreover that we can do this dynamically.
This contract, when initialized with an `ERC20DeployReady` instance, will result in exactly the same behavior implemented in the previous section. What is interesting about using `ERC20DeployReady` is that we can easily combine multiple supply mechanisms by assigning the role to multiple contracts, and moreover that we can do this dynamically.
TIP: To learn more about roles and permissioned systems, head to our xref:access-control.adoc[Access Control guide].
[[automating-the-reward]]
== Automating the Reward

View File

@ -13,19 +13,18 @@ Here's what our GLD token might look like.
[source,solidity]
----
pragma solidity ^0.5.0;
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";
contract GLDToken is ERC20, ERC20Detailed {
constructor(uint256 initialSupply) ERC20Detailed("Gold", "GLD", 18) public {
contract GLDToken is ERC20 {
constructor(uint256 initialSupply) ERC20("Gold", "GLD") public {
_mint(msg.sender, initialSupply);
}
}
----
Our contracts are often used via https://solidity.readthedocs.io/en/latest/contracts.html#inheritance[inheritance], and here we're reusing xref:api:token/ERC20.adoc#erc20[`ERC20`] for the basic standard implementation and xref:api:token/ERC20.adoc#ERC20Detailed[`ERC20Detailed`] to get the xref:api:token/ERC20.adoc#ERC20Detailed-name--[`name`], xref:api:token/ERC20.adoc#ERC20Detailed-symbol--[`symbol`], and xref:api:token/ERC20.adoc#ERC20Detailed-decimals--[`decimals`] properties. Additionally, we're creating an `initialSupply` of tokens, which will be assigned to the address that deploys the contract.
Our contracts are often used via https://solidity.readthedocs.io/en/latest/contracts.html#inheritance[inheritance], and here we're reusing xref:api:token/ERC20.adoc#erc20[`ERC20`] for both the basic standard implementation and the xref:api:token/ERC20.adoc#ERC20-name--[`name`], xref:api:token/ERC20.adoc#ERC20-symbol--[`symbol`], and xref:api:token/ERC20.adoc#ERC20-decimals--[`decimals`] optional extensions. Additionally, we're creating an `initialSupply` of tokens, which will be assigned to the address that deploys the contract.
TIP: For a more complete discussion of ERC20 supply mechanisms, see xref:erc20-supply.adoc[Creating ERC20 Supply].
@ -53,7 +52,7 @@ We can also xref:api:token/ERC20.adoc#IERC20-transfer-address-uint256-[transfer]
Often, you'll want to be able to divide your tokens into arbitrary amounts: say, if you own `5 GLD`, you may want to send `1.5 GLD` to a friend, and keep `3.5 GLD` to yourself. Unfortunately, Solidity and the EVM do not support this behavior: only integer (whole) numbers can be used, which poses an issue. You may send `1` or `2` tokens, but not `1.5`.
To work around this, xref:api:token/ERC20.adoc#ERC20Detailed[`ERC20Detailed`] provides a xref:api:token/ERC20.adoc#ERC20Detailed-decimals--[`decimals`] field, which is used to specify how many decimal places a token has. To be able to transfer `1.5 GLD`, `decimals` must be at least `1`, since that number has a single decimal place.
To work around this, xref:api:token/ERC20.adoc#ERC20[`ERC20`] provides a xref:api:token/ERC20.adoc#ERC20-decimals--[`decimals`] field, which is used to specify how many decimal places a token has. To be able to transfer `1.5 GLD`, `decimals` must be at least `1`, since that number has a single decimal place.
How can this be achieved? It's actually very simple: a token contract can use larger integer values, so that a balance of `50` will represent `5 GLD`, a transfer of `15` will correspond to `1.5 GLD` being sent, and so on.
@ -61,6 +60,8 @@ It is important to understand that `decimals` is _only used for display purposes
You'll probably want to use a `decimals` value of `18`, just like Ether and most ERC20 token contracts in use, unless you have a very special reason not to. When minting tokens or transferring them around, you will be actually sending the number `num GLD * 10^decimals`.
NOTE: By default, `ERC20` uses a value of `18` for `decimals`. To use a different value, you will need to call xref:api:token/ERC20.adoc#ERC20-_setupDecimals-uint8-[_setupDecimals] in your constructor.
So if you want to send `5` tokens using a token contract with 18 decimals, the the method to call will actually be:
```solidity

View File

@ -12,16 +12,16 @@ Here's what a contract for tokenized items might look like:
[source,solidity]
----
pragma solidity ^0.5.0;
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract GameItem is ERC721Full {
contract GameItem is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721Full("GameItem", "ITM") public {
constructor() ERC721("GameItem", "ITM") public {
}
function awardItem(address player, string memory tokenURI) public returns (uint256) {
@ -36,7 +36,7 @@ contract GameItem is ERC721Full {
}
----
The xref:api:token/ERC721.adoc#ERC721Full[`ERC721Full`] contract includes all standard extensions, and is probably the one you want to use. In particular, it includes xref:api:token/ERC721.adoc#ERC721Metadata[`ERC721Metadata`], which provides the xref:api:token/ERC721.adoc#ERC721Metadata-_setTokenURI-uint256-string-[`_setTokenURI`] method we use to store an item's metadata.
The xref:api:token/ERC721.adoc#ERC721[`ERC721`] contract includes all standard extensions (xref:api:token/ERC721.adoc#IERC721Metadata[`IERC721Metadata`] and xref:api:token/ERC721.adoc#IERC721Enumerable[`IERC721Enumerable`]). That's where the xref:api:token/ERC721.adoc#ERC721-_setTokenURI-uint256-string-[`_setTokenURI`] method comes from: we use it to store an item's metadata.
Also note that, unlike ERC20, ERC721 lacks a `decimals` field, since each token is distinct and cannot be partitioned.

View File

@ -102,17 +102,22 @@ NOTE: Always use `_preRelayedCall` and `_postRelayedCall` functions. Internal `
=== How to Use `GSNRecipientERC20Fee`
Your GSN recipient contract needs to inherit from `GSNRecipientERC20Fee` along with appropriate xref:access-control.adoc[access control] (for token minting), set the token details in the constructor of `GSNRecipientERC20Fee` and create a public `mint` function suitably protected by your chosen access control as per the following sample code (which uses the xref:api:access.adoc#MinterRole[MinterRole]):
Your GSN recipient contract needs to inherit from `GSNRecipientERC20Fee` along with appropriate xref:access-control.adoc[access control] (for token minting), set the token details in the constructor of `GSNRecipientERC20Fee` and create a public `mint` function suitably protected by your chosen access control as per the following sample code (which uses xref:api:access.adoc#AccessControl[`AccessControl`]):
[source,solidity]
----
import "@openzeppelin/contracts/GSN/GSNRecipientERC20Fee";
import "@openzeppelin/contracts/access/AccessControl";
contract MyContract is GSNRecipientERC20Fee, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
contract MyContract is GSNRecipientERC20Fee, MinterRole {
constructor() public GSNRecipientERC20Fee("FeeToken", "FEE") {
_setupRole(MINTER_ROLE, _msgSender());
}
function mint(address account, uint256 amount) public onlyMinter {
function mint(address account, uint256 amount) public {
require(hasRole(MINTER_ROLE, _msgSender()));
_mint(account, amount);
}
}

View File

@ -26,13 +26,12 @@ Once installed, you can use the contracts in the library by importing them:
[source,solidity]
----
pragma solidity ^0.5.0;
pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721Mintable.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract MyNFT is ERC721Full, ERC721Mintable {
constructor() ERC721Full("MyNFT", "MNFT") public {
contract MyNFT is ERC721 {
constructor() ERC721("MyNFT", "MNFT") public {
}
}
----

View File

@ -28,7 +28,7 @@ Every several months a new major release may come out. These are not scheduled,
On the https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.0.0[OpenZeppelin 2.0 release], we committed ourselves to keeping a stable API. We aim to more precisely define what we understand by _stable_ and _API_ here, so users of the library can understand these guarantees and be confident their project won't break unexpectedly.
In a nutshell, the API being stable means _if your project is working today, it will continue to do so_. New contracts and features will be added in minor releases, but only in a backwards compatible way. The exception to this rule are contracts in the xref:api:drafts.adoc[Drafts] category, which should be considered unstable.
In a nutshell, the API being stable means _if your project is working today, it will continue to do so_. New contracts and features will be added in minor releases, but only in a backwards compatible way.
[[versioning-scheme]]
=== Versioning Scheme
@ -54,7 +54,7 @@ Finally, sometimes language limitations will force us to e.g. make `internal` a
[[libraries]]
=== Libraries
Some of our Solidity libraries use `struct`s to handle internal data that should not be accessed directly (e.g. `Roles`). There's an https://github.com/ethereum/solidity/issues/4637[open issue] in the Solidity repository requesting a language feature to prevent said access, but it looks like it won't be implemented any time soon. Because of this, we will use leading underscores and mark said `struct` s to make it clear to the user that its contents and layout are _not_ part of the API.
Some of our Solidity libraries use ``struct``s to handle internal data that should not be accessed directly (e.g. `Roles`). There's an https://github.com/ethereum/solidity/issues/4637[open issue] in the Solidity repository requesting a language feature to prevent said access, but it looks like it won't be implemented any time soon. Because of this, we will use leading underscores and mark said `struct` s to make it clear to the user that its contents and layout are _not_ part of the API.
[[events]]
=== Events

View File

@ -90,11 +90,11 @@ If you want to Escrow some funds, check out xref:api:payment.adoc#Escrow[`Escrow
[[collections]]
== Collections
If you need support for more powerful collections than Solidity's native arrays and mappings, take a look at xref:api:utils.adoc#EnumerableSet[`EnumerableSet`]. It is similar to a mapping in that it stores and removes elements in constant time and doesn't allow for repeated entries, but it also supports _enumeration_, which means you can easily query all elements of the set both on and off-chain.
If you need support for more powerful collections than Solidity's native arrays and mappings, take a look at xref:api:utils.adoc#EnumerableSet[`EnumerableSet`] and xref:api:utils.adoc#EnumerableMap[`EnumerableMap`]. They are similar to mappings in that they store and remove elements in constant time and don't allow for repeated entries, but they also supports _enumeration_, which means you can easily query all stored entries both on and off-chain.
[[misc]]
== Misc
Want to check if an address is a contract? Use xref:api:utils.adoc#Address[`Address`] and xref:api:utils.adoc#Address-isContract-address-[`Address.isContract()`].
Want to keep track of some numbers that increment by 1 every time you want another one? Check out xref:api:drafts.adoc#Counter[`Counter`]. This is useful for lots of things, like creating incremental identifiers, as shown on the xref:721.adoc[ERC721 guide].
Want to keep track of some numbers that increment by 1 every time you want another one? Check out xref:api:utils.adoc#Counters[`Counters`]. This is useful for lots of things, like creating incremental identifiers, as shown on the xref:erc721.adoc[ERC721 guide].