Commit 6e901efa by Francisco Giordano

Merge tag 'v2.4.0' of github.com:OpenZeppelin/openzeppelin-solidity

2.4.0
parents abaade2c cdf655f7
comment: off
coverage:
range: "100...100"
--- ---
name: Bug report name: Bug report
about: Report a bug in OpenZeppelin about: Report a bug in OpenZeppelin Contracts
--- ---
<!-- Briefly describe the issue you're experiencing. Tell us what you were trying to do and what happened instead. --> <!-- Briefly describe the issue you're experiencing. Tell us what you were trying to do and what happened instead. -->
<!-- Remember, this is not a place to ask for help debugging code. For that, we welcome you in the Zeppelin Forum: https://forum.zeppelin.solutions/. --> <!-- Remember, this is not a place to ask for help debugging code. For that, we welcome you in the OpenZeppelin Community Forum: https://forum.openzeppelin.com/. -->
**💻 Environment** **💻 Environment**
<!-- Tell us what version of OpenZeppelin you're using, and how you're using it: Truffle, Remix, etc. --> <!-- Tell us what version of OpenZeppelin Contracts you're using, and how you're using it: Truffle, Remix, etc. -->
**📝 Details** **📝 Details**
......
--- ---
name: Feature request name: Feature request
about: Suggest an idea for OpenZeppelin about: Suggest an idea for OpenZeppelin Contracts
--- ---
...@@ -11,4 +11,4 @@ about: Suggest an idea for OpenZeppelin ...@@ -11,4 +11,4 @@ about: Suggest an idea for OpenZeppelin
<!-- Please describe your feature request in detail. --> <!-- Please describe your feature request in detail. -->
<!-- Make sure that you have reviewed the OpenZeppelin Contributor Guidelines. --> <!-- Make sure that you have reviewed the OpenZeppelin Contributor Guidelines. -->
<!-- https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CONTRIBUTING.md --> <!-- https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md -->
...@@ -13,7 +13,7 @@ Fixes # ...@@ -13,7 +13,7 @@ Fixes #
<!-- 3. Before submitting, please make sure that you have: <!-- 3. Before submitting, please make sure that you have:
- reviewed the OpenZeppelin Contributor Guidelines - reviewed the OpenZeppelin Contributor Guidelines
(https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/CONTRIBUTING.md), (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md),
- added tests where applicable to test new functionality, - added tests where applicable to test new functionality,
- made sure that your contracts are well-documented, - made sure that your contracts are well-documented,
- run the Solidity linter (`npm run lint:sol`) and fixed any issues, - run the Solidity linter (`npm run lint:sol`) and fixed any issues,
......
...@@ -43,6 +43,10 @@ build/ ...@@ -43,6 +43,10 @@ build/
# IntelliJ IDE # IntelliJ IDE
.idea .idea
# docsite artifacts # docs artifacts
docsite-build docs/modules/api
docs/api openzeppelin-docs
# only used to package @openzeppelin/contracts
contracts/build/
contracts/README.md
{ {
"extends": "default", "extends": "solhint:recommended",
"rules": { "rules": {
"indent": ["error", 4], "indent": ["error", 4],
"func-order": false, "func-order": "off",
"bracket-align": false, "bracket-align": "off",
"compiler-fixed": false, "compiler-fixed": "off",
"no-simple-event-func-name": false, "no-simple-event-func-name": "off",
"separate-by-one-line-in-contract": false, "separate-by-one-line-in-contract": "off",
"two-lines-top-level-separator": false "two-lines-top-level-separator": "off",
"mark-callable-contracts": "off",
"compiler-version": ["error", "^0.5.0"]
} }
} }
# Changelog # Changelog
## 2.4.0 (2019-10-29)
### New features:
* `Address.toPayable`: added a helper to convert between address types without having to resort to low-level casting. ([#1773](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1773))
* Facilities to make metatransaction-enabled contracts through the Gas Station Network. ([#1844](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1844))
* `Address.sendValue`: added a replacement to Solidity's `transfer`, removing the fixed gas stipend. ([#1962](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1962))
* Added replacement for functions that don't forward all gas (which have been deprecated): ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976))
* `PullPayment.withdrawPaymentsWithGas(address payable payee)`
* `Escrow.withdrawWithGas(address payable payee)`
* `SafeMath`: added support for custom error messages to `sub`, `div` and `mod` functions. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828))
### Improvements:
* `Address.isContract`: switched from `extcodesize` to `extcodehash` for less gas usage. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802))
* `ERC20` and `ERC777` updated to throw custom errors on subtraction overflows. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828))
### Deprecations:
* Deprecated functions that don't forward all gas: ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976))
* `PullPayment.withdrawPayments(address payable payee)`
* `Escrow.withdraw(address payable payee)`
### Breaking changes:
* `Address` now requires a minimum Solidity compiler version of 0.5.5. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802))
* `SignatureBouncer` has been removed from drafts, both to avoid confusions with the GSN and `GSNRecipientSignature` (previously called `GSNBouncerSignature`) and because the API was not very clear. ([#1879](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1879))
## 2.3.0 (2019-05-27) ## 2.3.0 (2019-05-27)
### New features: ### New features:
......
...@@ -61,3 +61,9 @@ Any exception or additions specific to our project are documented below. ...@@ -61,3 +61,9 @@ Any exception or additions specific to our project are documented below.
Some standards (e.g. ERC20) use present tense, and in those cases the Some standards (e.g. ERC20) use present tense, and in those cases the
standard specification prevails. standard specification prevails.
* Interface names should have a capital I prefix.
```
interface IERC777 {
```
Contributing to OpenZeppelin Contributing to OpenZeppelin Contracts
======= =======
We really appreciate and value contributions to OpenZeppelin. Please take 5' to review the items listed below to make sure that your contributions are merged as soon as possible. We really appreciate and value contributions to OpenZeppelin Contracts. Please take 5' to review the items listed below to make sure that your contributions are merged as soon as possible.
## Contribution guidelines ## Contribution guidelines
Smart contracts manage value and are highly vulnerable to errors and attacks. We have very strict guidelines, please make sure to review them: ["Contribution guidelines wiki entry"](https://github.com/OpenZeppelin/openzeppelin-solidity/wiki/Contribution-guidelines). Smart contracts manage value and are highly vulnerable to errors and attacks. We have very strict [guidelines], please make sure to review them!
## Creating Pull Requests (PRs) ## Creating Pull Requests (PRs)
As a contributor, you are expected to fork this repository, work on your own fork and then submit pull requests. The pull requests will be reviewed and eventually merged into the main repo. See ["Fork-a-Repo"](https://help.github.com/articles/fork-a-repo/) for how this works. As a contributor, you are expected to fork this repository, work on your own fork and then submit pull requests. The pull requests will be reviewed and eventually merged into the main repo. See ["Fork-a-Repo"](https://help.github.com/articles/fork-a-repo/) for how this works.
*IMPORTANT*
* Please see ["Git flow wiki entry"](https://github.com/OpenZeppelin/openzeppelin-solidity/wiki/Git-flow) for understanding how to use branches in this repository.
## A typical workflow ## A typical workflow
1) Make sure your fork is up to date with the main repository: 1) Make sure your fork is up to date with the main repository:
``` ```
cd openzeppelin-solidity cd openzeppelin-contracts
git remote add upstream https://github.com/OpenZeppelin/openzeppelin-solidity.git git remote add upstream https://github.com/OpenZeppelin/openzeppelin-contracts.git
git fetch upstream git fetch upstream
git pull --rebase upstream master git pull --rebase upstream master
``` ```
NOTE: The directory `openzeppelin-solidity` represents your fork's local copy. NOTE: The directory `openzeppelin-contracts` represents your fork's local copy.
2) Branch out from `master` into `fix/some-bug-#123`: 2) Branch out from `master` into `fix/some-bug-#123`:
(Postfixing #123 will associate your PR with the issue #123 and make everyone's life easier =D) (Postfixing #123 will associate your PR with the issue #123 and make everyone's life easier =D)
...@@ -32,7 +29,7 @@ NOTE: The directory `openzeppelin-solidity` represents your fork's local copy. ...@@ -32,7 +29,7 @@ NOTE: The directory `openzeppelin-solidity` represents your fork's local copy.
git checkout -b fix/some-bug-#123 git checkout -b fix/some-bug-#123
``` ```
3) Make your changes, add your files, commit and push to your fork. 3) Make your changes, add your files, commit, and push to your fork.
``` ```
git add SomeFile.js git add SomeFile.js
...@@ -40,19 +37,35 @@ git commit "Fix some bug #123" ...@@ -40,19 +37,35 @@ git commit "Fix some bug #123"
git push origin fix/some-bug-#123 git push origin fix/some-bug-#123
``` ```
4) Go to [github.com/OpenZeppelin/openzeppelin-solidity](https://github.com/OpenZeppelin/zeppelin-solidity) in your web browser and issue a new pull request. 4) Run tests, linter, etc. This can be done by running local continuous integration and make sure it passes.
```bash
npm test
npm run lint
```
*IMPORTANT* Read the PR template very carefully and make sure to follow all the instructions. These instructions or you can simply run CircleCI locally
refer to some very important conditions that your PR must meet in order to be accepted, such as making sure that all tests pass, JS linting tests pass, solidity linting tests pass, etc. ```bash
circleci local execute --job build
circleci local execute --job test
```
*Note*: requires installing CircleCI and docker locally on your machine.
5) Maintainers will review your code and possibly ask for changes before your code is pulled in to the main repository. We'll check that all tests pass, review the coding style, and check for general code correctness. If everything is OK, we'll merge your pull request and your code will be part of OpenZeppelin. 5) Go to [github.com/OpenZeppelin/openzeppelin-contracts](https://github.com/OpenZeppelin/openzeppelin-contracts) in your web browser and issue a new pull request.
*IMPORTANT* Read the PR template very carefully and make sure to follow all the instructions. These instructions
refer to some very important conditions that your PR must meet in order to be accepted, such as making sure that all tests pass, JS linting tests pass, Solidity linting tests pass, etc.
6) Maintainers will review your code and possibly ask for changes before your code is pulled in to the main repository. We'll check that all tests pass, review the coding style, and check for general code correctness. If everything is OK, we'll merge your pull request and your code will be part of OpenZeppelin.
*IMPORTANT* Please pay attention to the maintainer's feedback, since its a necessary step to keep up with the standards OpenZeppelin attains to. *IMPORTANT* Please pay attention to the maintainer's feedback, since its a necessary step to keep up with the standards OpenZeppelin attains to.
## All set! ## All set!
If you have any questions feel free to post them to github.com/OpenZeppelin/openzeppelin-solidity/issues. If you have any questions, feel free to post them to github.com/OpenZeppelin/openzeppelin-contracts/issues.
Finally, if you're looking to collaborate and want to find easy tasks to start, look at the issues we marked as ["Good first issue"](https://github.com/OpenZeppelin/openzeppelin-solidity/labels/good%20first%20issue). Finally, if you're looking to collaborate and want to find easy tasks to start, look at the issues we marked as ["Good first issue"](https://github.com/OpenZeppelin/openzeppelin-contracts/labels/good%20first%20issue).
Thanks for your time and code! Thanks for your time and code!
[guidelines]: GUIDELINES.md
We're building an improved documentation website. It's still in development and Documentation is hosted at https://docs.openzeppelin.com/contracts.
contributions will be really appreciated.
All of the content for the site is in this repository. The guides are in the All of the content for the site is in this repository. The guides are in the
[docs](/docs) directory, and the API Reference is extracted from comments in [docs](/docs) directory, and the API Reference is extracted from comments in
the source code. If you want to help improve the content, this is the the source code. If you want to help improve the content, this is the
repository you should be contributing to. repository you should be contributing to.
[`solidity-docgen`](https://github.com/OpenZeppelin/solidity-docgen/tree/next) is the [`solidity-docgen`](https://github.com/OpenZeppelin/solidity-docgen) is the
program that extracts the API Reference from source code. program that extracts the API Reference from source code.
The [`openzeppelin-docsite`](https://github.com/OpenZeppelin/openzeppelin-docsite/tree/next) The [`docs.openzeppelin.com`](https://github.com/OpenZeppelin/docs.openzeppelin.com)
repository hosts the configuration for Docusaurus, the static site generator repository hosts the configuration for the entire site, which includes
that we use. documetation for all of the OpenZeppelin projects.
To run the docsite locally you should run `npm run docsite start` on this To run the docs locally you should run `npm run docs start` on this
repository. This will live reload as the guides are edited, but not with repository.
changes to the source code comments, for that you need to restart the server.
This should be improved eventually (contributions welcome!).
Design Guidelines
=======
These are some global design goals in OpenZeppelin.
#### D0 - Security in Depth
We strive to provide secure, tested, audited code. To achieve this, we need to match intention with function. Thus, documentation, code clarity, community review and security discussions are fundamental.
#### D1 - Simple and Modular
Simpler code means easier audits, and better understanding of what each component does. We look for small files, small contracts, and small functions. If you can separate a contract into two independent functionalities you should probably do it.
#### D2 - Naming Matters
We take our time with picking names. Code is going to be written once, and read hundreds of times. Renaming for clarity is encouraged.
#### D3 - Tests
Write tests for all your code. We encourage Test Driven Development so we know when our code is right. Even though not all code in the repository is tested at the moment, we aim to test every line of code in the future.
#### D4 - Check preconditions and post-conditions
A very important way to prevent vulnerabilities is to catch a contract’s inconsistent state as early as possible. This is why we want functions to check pre- and post-conditions for executing its logic. When writing code, ask yourself what you are expecting to be true before and after the function runs, and express it in code.
#### D5 - Code Consistency
Consistency on the way classes are used is paramount to an easier understanding of the library. The codebase should be as unified as possible. Read existing code and get inspired before you write your own. Follow the style guidelines. Don’t hesitate to ask for help on how to best write a specific piece of code.
#### D6 - Regular Audits
Following good programming practices is a way to reduce the risk of vulnerabilities, but professional code audits are still needed. We will perform regular code audits on major releases, and hire security professionals to provide independent review.
## Style Guidelines
The design guidelines have quite a high abstraction level. These style guidelines are more concrete and easier to apply, and also more opinionated.
### General
#### G0 - Default to Solidity's official style guide.
Follow the official Solidity style guide: https://solidity.readthedocs.io/en/latest/style-guide.html
#### G1 - No Magic Constants
Avoid constants in the code as much as possible. Magic strings are also magic constants.
#### G2 - Code that Fails Early
We ask our code to fail as soon as possible when an unexpected input was provided or unexpected state was found.
#### G3 - Internal Amounts Must be Signed Integers and Represent the Smallest Units.
Avoid representation errors by always dealing with weis when handling ether. GUIs can convert to more human-friendly representations. Use Signed Integers (int) to prevent underflow problems.
### Testing
#### T1 - Tests Must be Written Elegantly
Style guidelines are not relaxed for tests. Tests are a good way to show how to use the library, and maintaining them is extremely necessary.
Don't write long tests, write helper functions to make them be as short and concise as possible (they should take just a few lines each), and use good variable names.
#### T2 - Tests Must not be Random
Inputs for tests should not be generated randomly. Accounts used to create test contracts are an exception, those can be random. Also, the type and structure of outputs should be checked.
...@@ -90,7 +90,7 @@ On our site you will find a few [guides] to learn about the different parts of O ...@@ -90,7 +90,7 @@ On our site you will find a few [guides] to learn about the different parts of O
## Security ## Security
OpenZeppelin Contracts is maintained by [OpenZeppelin](https://openzeppelin.com) the company, and developed following our high standards for code quality and security. OpenZeppelin Contracts is meant to provide tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problems you might experience. OpenZeppelin Contracts is maintained by [OpenZeppelin] the company, and developed following our high standards for code quality and security. OpenZeppelin Contracts is meant to provide tested and community-audited code, but please use common sense when doing anything that deals with real money! We take no responsibility for your implementation decisions and any security problems you might experience.
The core development principles and strategies that OpenZeppelin Contracts is based on include: security in depth, simple and modular code, clarity-driven naming conventions, comprehensive unit testing, pre-and-post-condition sanity checks, code consistency, and regular audits. The core development principles and strategies that OpenZeppelin Contracts is based on include: security in depth, simple and modular code, clarity-driven naming conventions, comprehensive unit testing, pre-and-post-condition sanity checks, code consistency, and regular audits.
...@@ -106,8 +106,8 @@ OpenZeppelin exists thanks to its contributors. There are many ways you can part ...@@ -106,8 +106,8 @@ OpenZeppelin exists thanks to its contributors. There are many ways you can part
OpenZeppelin is released under the [MIT License](LICENSE). OpenZeppelin is released under the [MIT License](LICENSE).
[API docs]: https://docs.openzeppelin.org/v2.3.0/api/token/erc20 [API docs]: https://docs.openzeppelin.com/contracts/2.x/api/token/erc20
[guides]: https://docs.openzeppelin.org/v2.3.0/get-started [guides]: https://docs.openzeppelin.com/contracts/2.x/
[forum]: https://forum.zeppelin.solutions [forum]: https://forum.openzeppelin.com
[Zeppelin]: https://zeppelin.solutions [OpenZeppelin]: https://openzeppelin.com
[contribution guide]: CONTRIBUTING.md [contribution guide]: CONTRIBUTING.md
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
This document describes our release process, and contains the steps to be followed by an OpenZeppelin maintainer at the several stages of a release. This document describes our release process, and contains the steps to be followed by an OpenZeppelin maintainer at the several stages of a release.
We release a new version of OpenZeppelin monthly. Release cycles are tracked in the [issue milestones](https://github.com/OpenZeppelin/openzeppelin-solidity/milestones). We release a new version of OpenZeppelin monthly. Release cycles are tracked in the [issue milestones](https://github.com/OpenZeppelin/openzeppelin-contracts/milestones).
Each release has at least one release candidate published first, intended for community review and any critical fixes that may come out of it. At the moment we leave 1 week between the first release candidate and the final release. Each release has at least one release candidate published first, intended for community review and any critical fixes that may come out of it. At the moment we leave 1 week between the first release candidate and the final release.
...@@ -32,7 +32,7 @@ git push upstream release-vX.Y.Z ...@@ -32,7 +32,7 @@ git push upstream release-vX.Y.Z
git push upstream vX.Y.Z-rc.R git push upstream vX.Y.Z-rc.R
``` ```
Draft the release notes in our [GitHub releases](https://github.com/OpenZeppelin/openzeppelin-solidity/releases). Make sure to mark it as a pre-release! Try to be consistent with our previous release notes in the title and format of the text. Release candidates don't need a detailed changelog, but make sure to include a link to GitHub's compare page. Draft the release notes in our [GitHub releases](https://github.com/OpenZeppelin/openzeppelin-contracts/releases). Make sure to mark it as a pre-release! Try to be consistent with our previous release notes in the title and format of the text. Release candidates don't need a detailed changelog, but make sure to include a link to GitHub's compare page.
Once the CI run for the new tag is green, publish on npm under the `next` tag. You should see the contracts compile automatically. Once the CI run for the new tag is green, publish on npm under the `next` tag. You should see the contracts compile automatically.
...@@ -76,7 +76,7 @@ Publish the release notes on GitHub and ask our community manager to announce th ...@@ -76,7 +76,7 @@ Publish the release notes on GitHub and ask our community manager to announce th
Delete the `next` tag in the npm package as there is no longer a release candidate. Delete the `next` tag in the npm package as there is no longer a release candidate.
``` ```
npm dist-tag rm --otp $2FA_CODE openzeppelin-solidity next npm dist-tag rm --otp $2FA_CODE @openzeppelin/contracts next
``` ```
## Merging the release branch ## Merging the release branch
......
## Architecture
The following provides visibility into how OpenZeppelin's contracts are organized:
- **access** - Smart contracts that enable functionality that can be used for selective restrictions and basic authorization control functions.
- **crowdsale** - A collection of smart contracts used to manage token crowdsales that allow investors to purchase tokens with ETH. Includes a base contract which implements fundamental crowdsale functionality in its simplest form. The base contract can be extended in order to satisfy your crowdsale’s specific requirements.
- **distribution** - Includes extensions of the base crowdsale contract which can be used to customize the completion of a crowdsale.
- **emission** - Includes extensions of the base crowdsale contract which can be used to mint and manage how tokens are issued to purchasers.
- **price** - Includes extensions of the crowdsale contract that can be used to manage changes in token prices.
- **validation** - Includes extensions of the crowdsale contract that can be used to enforce restraints and limit access to token purchases.
- **examples** - A collection of simple smart contracts that demonstrate how to add new features to base contracts through multiple inheritance.
- **introspection** - An interface that can be used to make a contract comply with the ERC-165 standard as well as a contract that implements ERC-165 using a lookup table.
- **lifecycle** - A collection of base contracts used to manage the existence and behavior of your contracts and their funds.
- **math** - Libraries with safety checks on operations that throw on errors.
- **mocks** - A collection of abstract contracts that are primarily used for unit testing. They also serve as good usage examples and demonstrate how to combine contracts with inheritance when developing your own custom applications.
- **ownership** - A collection of smart contracts that can be used to manage contract and token ownership
- **payment** - A collection of smart contracts that can be used to manage payments through escrow arrangements, withdrawals, and claims. Includes support for both single payees and multiple payees.
- **proposals** - A collection of smart contracts that reflect community Ethereum Improvement Proposals (EIPs). These contracts are under development and standardization. They are not recommended for production, but they are useful for experimentation with pending EIP standards. Go [here](https://github.com/OpenZeppelin/openzeppelin-solidity/wiki/ERC-Process) for more information.
- **token** - A collection of approved ERC standard tokens -- their interfaces and implementations.
- **ERC20** - A standard interface for fungible tokens:
- *Interfaces* - Includes the ERC-20 token standard basic interface. I.e., what the contract’s ABI can represent.
- *Implementations* - Includes ERC-20 token implementations that include all required and some optional ERC-20 functionality.
- **ERC721** - A standard interface for non-fungible tokens
- *Interfaces* - Includes the ERC-721 token standard basic interface. I.e., what the contract’s ABI can represent.
- *Implementations* - Includes ERC-721 token implementations that include all required and some optional ERC-721 functionality.
...@@ -3,7 +3,7 @@ pragma solidity ^0.5.0; ...@@ -3,7 +3,7 @@ pragma solidity ^0.5.0;
/* /*
* @dev Provides information about the current execution context, including the * @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available * sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they not should not be accessed in such a direct * via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and * manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application * paying for execution may not be the actual sender (as far as an application
* is concerned). * is concerned).
...@@ -12,11 +12,11 @@ pragma solidity ^0.5.0; ...@@ -12,11 +12,11 @@ pragma solidity ^0.5.0;
*/ */
contract Context { contract Context {
// Empty internal constructor, to prevent people from mistakenly deploying // Empty internal constructor, to prevent people from mistakenly deploying
// an instance of this contract, with should be used via inheritance. // an instance of this contract, which should be used via inheritance.
constructor () internal { } constructor () internal { }
// solhint-disable-previous-line no-empty-blocks // solhint-disable-previous-line no-empty-blocks
function _msgSender() internal view returns (address) { function _msgSender() internal view returns (address payable) {
return msg.sender; return msg.sender;
} }
......
pragma solidity ^0.5.0;
import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./Context.sol";
/*
* @dev Enables GSN support on `Context` contracts by recognizing calls from
* RelayHub and extracting the actual sender and call data from the received
* calldata.
*
* > This contract does not perform all required tasks to implement a GSN
* recipient contract: end users should use `GSNRecipient` instead.
*/
contract GSNContext is Initializable, Context {
// We use a random storage slot to allow proxy contracts to enable GSN support in an upgrade without changing their
// storage layout. This value is calculated as: keccak256('gsn.relayhub.address'), minus 1.
bytes32 private constant RELAY_HUB_ADDRESS_STORAGE_SLOT = 0x06b7792c761dcc05af1761f0315ce8b01ac39c16cc934eb0b2f7a8e71414f262;
event RelayHubChanged(address indexed oldRelayHub, address indexed newRelayHub);
function initialize() public initializer {
if (_getRelayHub() == address(0)) {
setDefaultRelayHub();
}
}
function setDefaultRelayHub() public {
_upgradeRelayHub(0xD216153c06E857cD7f72665E0aF1d7D82172F494);
}
function _getRelayHub() internal view returns (address relayHub) {
bytes32 slot = RELAY_HUB_ADDRESS_STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
relayHub := sload(slot)
}
}
function _upgradeRelayHub(address newRelayHub) internal {
address currentRelayHub = _getRelayHub();
require(newRelayHub != address(0), "GSNContext: new RelayHub is the zero address");
require(newRelayHub != currentRelayHub, "GSNContext: new RelayHub is the current one");
emit RelayHubChanged(currentRelayHub, newRelayHub);
bytes32 slot = RELAY_HUB_ADDRESS_STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, newRelayHub)
}
}
// Overrides for Context's functions: when called from RelayHub, sender and
// data require some pre-processing: the actual sender is stored at the end
// of the call data, which in turns means it needs to be removed from it
// when handling said data.
function _msgSender() internal view returns (address) {
if (msg.sender != _getRelayHub()) {
return msg.sender;
} else {
return _getRelayedCallSender();
}
}
function _msgData() internal view returns (bytes memory) {
if (msg.sender != _getRelayHub()) {
return msg.data;
} else {
return _getRelayedCallData();
}
}
function _getRelayedCallSender() private pure returns (address result) {
// We need to read 20 bytes (an address) located at array index msg.data.length - 20. In memory, the array
// is prefixed with a 32-byte length value, so we first add 32 to get the memory read index. However, doing
// so would leave the address in the upper 20 bytes of the 32-byte word, which is inconvenient and would
// require bit shifting. We therefore subtract 12 from the read index so the address lands on the lower 20
// bytes. This can always be done due to the 32-byte prefix.
// The final memory read index is msg.data.length - 20 + 32 - 12 = msg.data.length. Using inline assembly is the
// easiest/most-efficient way to perform this operation.
// These fields are not accessible from assembly
bytes memory array = msg.data;
uint256 index = msg.data.length;
// solhint-disable-next-line no-inline-assembly
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
result := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
}
return result;
}
function _getRelayedCallData() private pure returns (bytes memory) {
// RelayHub appends the sender address at the end of the calldata, so in order to retrieve the actual msg.data,
// we must strip the last 20 bytes (length of an address type) from it.
uint256 actualDataLength = msg.data.length - 20;
bytes memory actualData = new bytes(actualDataLength);
for (uint256 i = 0; i < actualDataLength; ++i) {
actualData[i] = msg.data[i];
}
return actualData;
}
}
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
import "@openzeppelin/upgrades/contracts/Initializable.sol"; import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./GSNBouncerBase.sol";
import "../../math/SafeMath.sol"; import "./GSNRecipient.sol";
import "../../ownership/Secondary.sol"; import "../math/SafeMath.sol";
import "../../token/ERC20/SafeERC20.sol"; import "../ownership/Secondary.sol";
import "../../token/ERC20/ERC20.sol"; import "../token/ERC20/SafeERC20.sol";
import "../../token/ERC20/ERC20Detailed.sol"; import "../token/ERC20/ERC20.sol";
import "../token/ERC20/ERC20Detailed.sol";
contract GSNBouncerERC20Fee is Initializable, GSNBouncerBase {
/**
* @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that charges transaction fees in a special purpose ERC20
* token, which we refer to as the gas payment token. The amount charged is exactly the amount of Ether charged to the
* recipient. This means that the token is essentially pegged to the value of Ether.
*
* The distribution strategy of the gas payment token to users is not defined by this contract. It's a mintable token
* whose only minter is the recipient, so the strategy must be implemented in a derived contract, making use of the
* internal {_mint} function.
*/
contract GSNRecipientERC20Fee is Initializable, GSNRecipient {
using SafeERC20 for __unstable__ERC20PrimaryAdmin; using SafeERC20 for __unstable__ERC20PrimaryAdmin;
using SafeMath for uint256; using SafeMath for uint256;
enum GSNBouncerERC20FeeErrorCodes { enum GSNRecipientERC20FeeErrorCodes {
INSUFFICIENT_BALANCE INSUFFICIENT_BALANCE
} }
// We use a random storage slot to allow proxy contracts to enable GSN support in an upgrade without changing their __unstable__ERC20PrimaryAdmin private _token;
// storage layout. This value is calculated as: keccak256('gsn.bouncer.signature.token'), minus 1.
bytes32 constant private TOKEN_STORAGE_SLOT = 0xd918b70a5a5c95a8c0cac8acbdd59e1b4acd0645f53c0461d64b41f8825c8828; /**
* @dev The arguments to the constructor are the details that the gas payment token will have: `name` and `symbol`. `decimals` is hard-coded to 18.
*/
function initialize(string memory name, string memory symbol) public initializer {
if (_token == __unstable__ERC20PrimaryAdmin(0)) {
_token = new __unstable__ERC20PrimaryAdmin(name, symbol, 18, address(this));
}
function initialize(string memory name, string memory symbol, uint8 decimals) public initializer { GSNRecipient.initialize();
// TODO: Should we inject this token, instead of creating it, in order to make it upgradeable?
// However, that would mean removing it from unstable and making in an official contract
_setToken(new __unstable__ERC20PrimaryAdmin(name, symbol, decimals));
} }
/**
* @dev Returns the gas payment token.
*/
function token() public view returns (IERC20) { function token() public view returns (IERC20) {
return IERC20(_getToken()); return IERC20(_token);
} }
/**
* @dev Internal function that mints the gas payment token. Derived contracts should expose this function in their public API, with proper access control mechanisms.
*/
function _mint(address account, uint256 amount) internal { function _mint(address account, uint256 amount) internal {
_getToken().mint(account, amount); _token.mint(account, amount);
} }
/**
* @dev Ensures that only users with enough gas payment token balance can have transactions relayed through the GSN.
*/
function acceptRelayedCall( function acceptRelayedCall(
address, address,
address from, address from,
...@@ -49,20 +71,29 @@ contract GSNBouncerERC20Fee is Initializable, GSNBouncerBase { ...@@ -49,20 +71,29 @@ contract GSNBouncerERC20Fee is Initializable, GSNBouncerBase {
view view
returns (uint256, bytes memory) returns (uint256, bytes memory)
{ {
if (_getToken().balanceOf(from) < maxPossibleCharge) { if (_token.balanceOf(from) < maxPossibleCharge) {
return _rejectRelayedCall(uint256(GSNBouncerERC20FeeErrorCodes.INSUFFICIENT_BALANCE)); return _rejectRelayedCall(uint256(GSNRecipientERC20FeeErrorCodes.INSUFFICIENT_BALANCE));
} }
return _approveRelayedCall(abi.encode(from, maxPossibleCharge, transactionFee, gasPrice)); return _approveRelayedCall(abi.encode(from, maxPossibleCharge, transactionFee, gasPrice));
} }
/**
* @dev Implements the precharge to the user. The maximum possible charge (depending on gas limit, gas price, and
* fee) will be deducted from the user balance of gas payment token. Note that this is an overestimation of the
* actual charge, necessary because we cannot predict how much gas the execution will actually need. The remainder
* is returned to the user in {_postRelayedCall}.
*/
function _preRelayedCall(bytes memory context) internal returns (bytes32) { function _preRelayedCall(bytes memory context) internal returns (bytes32) {
(address from, uint256 maxPossibleCharge) = abi.decode(context, (address, uint256)); (address from, uint256 maxPossibleCharge) = abi.decode(context, (address, uint256));
// The maximum token charge is pre-charged from the user // The maximum token charge is pre-charged from the user
_getToken().safeTransferFrom(from, address(this), maxPossibleCharge); _token.safeTransferFrom(from, address(this), maxPossibleCharge);
} }
/**
* @dev Returns to the user the extra amount that was previously charged, once the actual execution cost is known.
*/
function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal { function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal {
(address from, uint256 maxPossibleCharge, uint256 transactionFee, uint256 gasPrice) = (address from, uint256 maxPossibleCharge, uint256 transactionFee, uint256 gasPrice) =
abi.decode(context, (address, uint256, uint256, uint256)); abi.decode(context, (address, uint256, uint256, uint256));
...@@ -74,23 +105,7 @@ contract GSNBouncerERC20Fee is Initializable, GSNBouncerBase { ...@@ -74,23 +105,7 @@ contract GSNBouncerERC20Fee is Initializable, GSNBouncerBase {
actualCharge = actualCharge.sub(overestimation); actualCharge = actualCharge.sub(overestimation);
// After the relayed call has been executed and the actual charge estimated, the excess pre-charge is returned // After the relayed call has been executed and the actual charge estimated, the excess pre-charge is returned
_getToken().safeTransfer(from, maxPossibleCharge.sub(actualCharge)); _token.safeTransfer(from, maxPossibleCharge.sub(actualCharge));
}
function _getToken() private view returns (__unstable__ERC20PrimaryAdmin token) {
bytes32 slot = TOKEN_STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
token := sload(slot)
}
}
function _setToken(__unstable__ERC20PrimaryAdmin token) private {
bytes32 slot = TOKEN_STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, token)
}
} }
} }
...@@ -104,9 +119,9 @@ contract GSNBouncerERC20Fee is Initializable, GSNBouncerBase { ...@@ -104,9 +119,9 @@ contract GSNBouncerERC20Fee is Initializable, GSNBouncerBase {
contract __unstable__ERC20PrimaryAdmin is ERC20, ERC20Detailed, Secondary { contract __unstable__ERC20PrimaryAdmin is ERC20, ERC20Detailed, Secondary {
uint256 private constant UINT256_MAX = 2**256 - 1; uint256 private constant UINT256_MAX = 2**256 - 1;
constructor(string memory name, string memory symbol, uint8 decimals) public { constructor(string memory name, string memory symbol, uint8 decimals, address sender) public {
Secondary.initialize(msg.sender);
ERC20Detailed.initialize(name, symbol, decimals); ERC20Detailed.initialize(name, symbol, decimals);
Secondary.initialize(sender);
} }
// The primary account (GSNRecipientERC20Fee) can mint tokens // The primary account (GSNRecipientERC20Fee) can mint tokens
......
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
import "@openzeppelin/upgrades/contracts/Initializable.sol"; import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./GSNBouncerBase.sol";
import "../../cryptography/ECDSA.sol";
contract GSNBouncerSignature is Initializable, GSNBouncerBase { import "./GSNRecipient.sol";
import "../cryptography/ECDSA.sol";
/**
* @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that allows relayed transactions through when they are
* accompanied by the signature of a trusted signer. The intent is for this signature to be generated by a server that
* performs validations off-chain. Note that nothing is charged to the user in this scheme. Thus, the server should make
* sure to account for this in their economic and threat model.
*/
contract GSNRecipientSignature is Initializable, GSNRecipient {
using ECDSA for bytes32; using ECDSA for bytes32;
// We use a random storage slot to allow proxy contracts to enable GSN support in an upgrade without changing their address private _trustedSigner;
// storage layout. This value is calculated as: keccak256('gsn.bouncer.signature.trustedSigner'), minus 1.
bytes32 constant private TRUSTED_SIGNER_STORAGE_SLOT = 0xe7b237a4017a399d277819456dce32c2356236bbc518a6d84a9a8d1cfdf1e9c5;
enum GSNBouncerSignatureErrorCodes { enum GSNRecipientSignatureErrorCodes {
INVALID_SIGNER INVALID_SIGNER
} }
/**
* @dev Sets the trusted signer that is going to be producing signatures to approve relayed calls.
*/
function initialize(address trustedSigner) public initializer { function initialize(address trustedSigner) public initializer {
_setTrustedSigner(trustedSigner); require(trustedSigner != address(0), "GSNRecipientSignature: trusted signer is the zero address");
_trustedSigner = trustedSigner;
GSNRecipient.initialize();
} }
/**
* @dev Ensures that only transactions with a trusted signature can be relayed through the GSN.
*/
function acceptRelayedCall( function acceptRelayedCall(
address relay, address relay,
address from, address from,
...@@ -45,26 +59,18 @@ contract GSNBouncerSignature is Initializable, GSNBouncerBase { ...@@ -45,26 +59,18 @@ contract GSNBouncerSignature is Initializable, GSNBouncerBase {
getHubAddr(), // Prevents replays in multiple RelayHubs getHubAddr(), // Prevents replays in multiple RelayHubs
address(this) // Prevents replays in multiple recipients address(this) // Prevents replays in multiple recipients
); );
if (keccak256(blob).toEthSignedMessageHash().recover(approvalData) == _getTrustedSigner()) { if (keccak256(blob).toEthSignedMessageHash().recover(approvalData) == _trustedSigner) {
return _approveRelayedCall(); return _approveRelayedCall();
} else { } else {
return _rejectRelayedCall(uint256(GSNBouncerSignatureErrorCodes.INVALID_SIGNER)); return _rejectRelayedCall(uint256(GSNRecipientSignatureErrorCodes.INVALID_SIGNER));
} }
} }
function _getTrustedSigner() private view returns (address trustedSigner) { function _preRelayedCall(bytes memory) internal returns (bytes32) {
bytes32 slot = TRUSTED_SIGNER_STORAGE_SLOT; // solhint-disable-previous-line no-empty-blocks
// solhint-disable-next-line no-inline-assembly
assembly {
trustedSigner := sload(slot)
}
} }
function _setTrustedSigner(address trustedSigner) private { function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal {
bytes32 slot = TRUSTED_SIGNER_STORAGE_SLOT; // solhint-disable-previous-line no-empty-blocks
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, trustedSigner)
}
} }
} }
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
/* /**
* @dev Interface for a contract that will be called via the GSN from RelayHub. * @dev Base interface for a contract that will be called via the GSN from {IRelayHub}.
*
* TIP: You don't need to write an implementation yourself! Inherit from {GSNRecipient} instead.
*/ */
contract IRelayRecipient { contract IRelayRecipient {
/** /**
* @dev Returns the address of the RelayHub instance this recipient interacts with. * @dev Returns the address of the {IRelayHub} instance this recipient interacts with.
*/ */
function getHubAddr() public view returns (address); function getHubAddr() public view returns (address);
/**
* @dev Called by {IRelayHub} to validate if this recipient accepts being charged for a relayed call. Note that the
* recipient will be charged regardless of the execution result of the relayed call (i.e. if it reverts or not).
*
* The relay request was originated by `from` and will be served by `relay`. `encodedFunction` is the relayed call
* calldata, so its first four bytes are the function selector. The relayed call will be forwarded `gasLimit` gas,
* and the transaction executed with a gas price of at least `gasPrice`. `relay`'s fee is `transactionFee`, and the
* recipient will be charged at most `maxPossibleCharge` (in wei). `nonce` is the sender's (`from`) nonce for
* replay attack protection in {IRelayHub}, and `approvalData` is a optional parameter that can be used to hold a signature
* over all or some of the previous values.
*
* Returns a tuple, where the first value is used to indicate approval (0) or rejection (custom non-zero error code,
* values 1 to 10 are reserved) and the second one is data to be passed to the other {IRelayRecipient} functions.
*
* {acceptRelayedCall} is called with 50k gas: if it runs out during execution, the request will be considered
* rejected. A regular revert will also trigger a rejection.
*/
function acceptRelayedCall( function acceptRelayedCall(
address relay, address relay,
address from, address from,
...@@ -24,7 +43,32 @@ contract IRelayRecipient { ...@@ -24,7 +43,32 @@ contract IRelayRecipient {
view view
returns (uint256, bytes memory); returns (uint256, bytes memory);
/**
* @dev Called by {IRelayHub} on approved relay call requests, before the relayed call is executed. This allows to e.g.
* pre-charge the sender of the transaction.
*
* `context` is the second value returned in the tuple by {acceptRelayedCall}.
*
* Returns a value to be passed to {postRelayedCall}.
*
* {preRelayedCall} is called with 100k gas: if it runs out during exection or otherwise reverts, the relayed call
* will not be executed, but the recipient will still be charged for the transaction's cost.
*/
function preRelayedCall(bytes calldata context) external returns (bytes32); function preRelayedCall(bytes calldata context) external returns (bytes32);
function postRelayedCall(bytes calldata context, bool success, uint actualCharge, bytes32 preRetVal) external; /**
* @dev Called by {IRelayHub} on approved relay call requests, after the relayed call is executed. This allows to e.g.
* charge the user for the relayed call costs, return any overcharges from {preRelayedCall}, or perform
* contract-specific bookkeeping.
*
* `context` is the second value returned in the tuple by {acceptRelayedCall}. `success` is the execution status of
* the relayed call. `actualCharge` is an estimate of how much the recipient will be charged for the transaction,
* not including any gas used by {postRelayedCall} itself. `preRetVal` is {preRelayedCall}'s return value.
*
*
* {postRelayedCall} is called with 100k gas: if it runs out during execution or otherwise reverts, the relayed call
* and the call to {preRelayedCall} will be reverted retroactively, but the recipient will still be charged for the
* transaction's cost.
*/
function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external;
} }
= Gas Station Network (GSN)
_Available since v2.4.0._
This set of contracts provide all the tools required to make a contract callable via the https://gsn.openzeppelin.com[Gas Station Network].
TIP: If you're new to the GSN, head over to our xref:openzeppelin::gsn/what-is-the-gsn.adoc[overview of the system] and basic guide to xref:ROOT:gsn.adoc[creating a GSN-capable contract].
The core contract a recipient must inherit from is {GSNRecipient}: it includes all necessary interfaces, as well as some helper methods to make interacting with the GSN easier.
Utilities to make writing xref:ROOT:gsn-strategies.adoc[GSN strategies] easy are available in {GSNRecipient}, or you can simply use one of our pre-made strategies:
* {GSNRecipientERC20Fee} charges the end user for gas costs in an application-specific xref:ROOT:tokens.adoc#ERC20[ERC20 token]
* {GSNRecipientSignature} accepts all relayed calls that have been signed by a trusted third party (e.g. a private key in a backend)
You can also take a look at the two contract interfaces that make up the GSN protocol: {IRelayRecipient} and {IRelayHub}, but you won't need to use those directly.
== Recipient
{{GSNRecipient}}
== Strategies
{{GSNRecipientSignature}}
{{GSNRecipientERC20Fee}}
== Protocol
{{IRelayRecipient}}
{{IRelayHub}}
pragma solidity ^0.5.0;
import "../IRelayRecipient.sol";
/*
* @dev Base contract used to implement GSNBouncers.
*
* > This contract does not perform all required tasks to implement a GSN
* recipient contract: end users should use `GSNRecipient` instead.
*/
contract GSNBouncerBase is IRelayRecipient {
uint256 constant private RELAYED_CALL_ACCEPTED = 0;
uint256 constant private RELAYED_CALL_REJECTED = 11;
// How much gas is forwarded to postRelayedCall
uint256 constant internal POST_RELAYED_CALL_MAX_GAS = 100000;
// Base implementations for pre and post relayedCall: only RelayHub can invoke them, and data is forwarded to the
// internal hook.
/**
* @dev See `IRelayRecipient.preRelayedCall`.
*
* This function should not be overriden directly, use `_preRelayedCall` instead.
*
* * Requirements:
*
* - the caller must be the `RelayHub` contract.
*/
function preRelayedCall(bytes calldata context) external returns (bytes32) {
require(msg.sender == getHubAddr(), "GSNBouncerBase: caller is not RelayHub");
return _preRelayedCall(context);
}
/**
* @dev See `IRelayRecipient.postRelayedCall`.
*
* This function should not be overriden directly, use `_postRelayedCall` instead.
*
* * Requirements:
*
* - the caller must be the `RelayHub` contract.
*/
function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external {
require(msg.sender == getHubAddr(), "GSNBouncerBase: caller is not RelayHub");
_postRelayedCall(context, success, actualCharge, preRetVal);
}
/**
* @dev Return this in acceptRelayedCall to proceed with the execution of a relayed call. Note that this contract
* will be charged a fee by RelayHub
*/
function _approveRelayedCall() internal pure returns (uint256, bytes memory) {
return _approveRelayedCall("");
}
/**
* @dev See `GSNBouncerBase._approveRelayedCall`.
*
* This overload forwards `context` to _preRelayedCall and _postRelayedCall.
*/
function _approveRelayedCall(bytes memory context) internal pure returns (uint256, bytes memory) {
return (RELAYED_CALL_ACCEPTED, context);
}
/**
* @dev Return this in acceptRelayedCall to impede execution of a relayed call. No fees will be charged.
*/
function _rejectRelayedCall(uint256 errorCode) internal pure returns (uint256, bytes memory) {
return (RELAYED_CALL_REJECTED + errorCode, "");
}
// Empty hooks for pre and post relayed call: users only have to define these if they actually use them.
function _preRelayedCall(bytes memory) internal returns (bytes32) {
// solhint-disable-previous-line no-empty-blocks
}
function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal {
// solhint-disable-previous-line no-empty-blocks
}
/*
* @dev Calculates how much RelaHub will charge a recipient for using `gas` at a `gasPrice`, given a relayer's
* `serviceFee`.
*/
function _computeCharge(uint256 gas, uint256 gasPrice, uint256 serviceFee) internal pure returns (uint256) {
// The fee is expressed as a percentage. E.g. a value of 40 stands for a 40% fee, so the recipient will be
// charged for 1.4 times the spent amount.
return (gas * gasPrice * (100 + serviceFee)) / 100;
}
}
= Access
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
== Library
{{Roles}}
== Roles
{{CapperRole}}
{{MinterRole}}
{{PauserRole}}
{{SignerRole}}
{{WhitelistAdminRole}}
{{WhitelistedRole}}
---
sections:
- title: Library
contracts:
- Roles
- subdirectory: roles
---
> This page is incomplete. We're working to improve it for the next release. Stay tuned!
...@@ -145,6 +145,7 @@ contract Crowdsale is Initializable, Context, ReentrancyGuard { ...@@ -145,6 +145,7 @@ contract Crowdsale is Initializable, Context, ReentrancyGuard {
function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view { function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view {
require(beneficiary != address(0), "Crowdsale: beneficiary is the zero address"); require(beneficiary != address(0), "Crowdsale: beneficiary is the zero address");
require(weiAmount != 0, "Crowdsale: weiAmount is 0"); require(weiAmount != 0, "Crowdsale: weiAmount is 0");
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
} }
/** /**
......
= Crowdsales
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
== Core
{{Crowdsale}}
== Emission
{{AllowanceCrowdsale}}
{{MintedCrowdsale}}
== Validation
{{CappedCrowdsale}}
{{IndividuallyCappedCrowdsale}}
{{PausableCrowdsale}}
{{TimedCrowdsale}}
{{WhitelistCrowdsale}}
== Distribution
{{FinalizableCrowdsale}}
{{PostDeliveryCrowdsale}}
{{RefundableCrowdsale}}
{{RefundablePostDeliveryCrowdsale}}
---
title: Crowdsales
sections:
- title: Core
contracts:
- Crowdsale
- subdirectory: emission
- subdirectory: price
- subdirectory: validation
- subdirectory: distribution
---
> This page is incomplete. We're working to improve it for the next release. Stay tuned!
...@@ -15,15 +15,15 @@ library ECDSA { ...@@ -15,15 +15,15 @@ library ECDSA {
* this function rejects them by requiring the `s` value to be in the lower * this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28. * half order, and the `v` value to be either 27 or 28.
* *
* (.note) This call _does not revert_ if the signature is invalid, or * NOTE: This call _does not revert_ if the signature is invalid, or
* if the signer is otherwise unable to be retrieved. In those scenarios, * if the signer is otherwise unable to be retrieved. In those scenarios,
* the zero address is returned. * the zero address is returned.
* *
* (.warning) `hash` _must_ be the result of a hash operation for the * IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that * verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure * recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise) * this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling `toEthSignedMessageHash` on it. * be too long), and then calling {toEthSignedMessageHash} on it.
*/ */
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
// Check the signature length // Check the signature length
...@@ -69,10 +69,10 @@ library ECDSA { ...@@ -69,10 +69,10 @@ library ECDSA {
/** /**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This * @dev Returns an Ethereum Signed Message, created from a `hash`. This
* replicates the behavior of the * replicates the behavior of the
* [`eth_sign`](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign) * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
* JSON-RPC method. * JSON-RPC method.
* *
* See `recover`. * See {recover}.
*/ */
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash, // 32 is the length in bytes of hash,
......
= Cryptography
This collection of libraries provides simple and safe ways to use different cryptographic primitives.
== Libraries
{{ECDSA}}
{{MerkleProof}}
---
sections:
- title: Libraries
contracts:
- ECDSA
- MerkleProof
---
This collection of libraries provides simple and safe ways to use different cryptographic primitives.
...@@ -9,7 +9,7 @@ import "../math/SafeMath.sol"; ...@@ -9,7 +9,7 @@ import "../math/SafeMath.sol";
* of elements in a mapping, issuing ERC721 ids, or counting request ids. * of elements in a mapping, issuing ERC721 ids, or counting request ids.
* *
* Include with `using Counters for Counters.Counter;` * Include with `using Counters for Counters.Counter;`
* Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
* overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
* directly accessed. * directly accessed.
*/ */
......
...@@ -6,7 +6,7 @@ import "../../token/ERC20/IERC20.sol"; ...@@ -6,7 +6,7 @@ import "../../token/ERC20/IERC20.sol";
/** /**
* @title ERC-1047 Token Metadata * @title ERC-1047 Token Metadata
* @dev See https://eips.ethereum.org/EIPS/eip-1046 * @dev See https://eips.ethereum.org/EIPS/eip-1046
* @dev tokenURI must respond with a URI that implements https://eips.ethereum.org/EIPS/eip-1047 * @dev {tokenURI} must respond with a URI that implements https://eips.ethereum.org/EIPS/eip-1047
*/ */
contract ERC20Metadata is Initializable { contract ERC20Metadata is Initializable {
string private _tokenURI; string private _tokenURI;
......
...@@ -15,8 +15,8 @@ import "../math/Math.sol"; ...@@ -15,8 +15,8 @@ import "../math/Math.sol";
* migration to the new token contract. In this way, token holders "turn in" * migration to the new token contract. In this way, token holders "turn in"
* their old balance and will be minted an equal amount in the new token. * their old balance and will be minted an equal amount in the new token.
* The new token contract must be mintable. For the precise interface refer to * The new token contract must be mintable. For the precise interface refer to
* OpenZeppelin's ERC20Mintable, but the only functions that are needed are * OpenZeppelin's {ERC20Mintable}, but the only functions that are needed are
* `isMinter(address)` and `mint(address, amount)`. The migrator will check * {MinterRole-isMinter} and {ERC20Mintable-mint}. The migrator will check
* that it is a minter for the token. * that it is a minter for the token.
* The balance from the legacy token will be transferred to the migrator, as it * The balance from the legacy token will be transferred to the migrator, as it
* is migrated, and remain there forever. * is migrated, and remain there forever.
...@@ -25,6 +25,7 @@ import "../math/Math.sol"; ...@@ -25,6 +25,7 @@ import "../math/Math.sol";
* version of it using the OpenZeppelin SDK. To read more about how this can be done * version of it using the OpenZeppelin SDK. To read more about how this can be done
* using this implementation, please follow the official documentation site of * using this implementation, please follow the official documentation site of
* the OpenZeppelinSDK: https://docs.zeppelinos.org/docs/erc20_onboarding.html * the OpenZeppelinSDK: https://docs.zeppelinos.org/docs/erc20_onboarding.html
*
* Example of usage: * Example of usage:
* ``` * ```
* const migrator = await ERC20Migrator.new(legacyToken.address); * const migrator = await ERC20Migrator.new(legacyToken.address);
......
...@@ -8,14 +8,16 @@ import "../token/ERC20/ERC20.sol"; ...@@ -8,14 +8,16 @@ import "../token/ERC20/ERC20.sol";
/** /**
* @title ERC20 token with snapshots. * @title ERC20 token with snapshots.
* @dev Inspired by Jordi Baylina's MiniMeToken to record historical balances: * @dev Inspired by Jordi Baylina's
* https://github.com/Giveth/minime/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol * https://github.com/Giveth/minimd/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol[MiniMeToken]
* When a snapshot is made, the balances and totalSupply at the time of the snapshot are recorded for later * to record historical balances.
*
* When a snapshot is made, the balances and total supply at the time of the snapshot are recorded for later
* access. * access.
* *
* To make a snapshot, call the `snapshot` function, which will emit the `Snapshot` event and return a snapshot id. * To make a snapshot, call the {snapshot} function, which will emit the {Snapshot} event and return a snapshot id.
* To get the total supply from a snapshot, call the function `totalSupplyAt` with the snapshot id. * To get the total supply from a snapshot, call the function {totalSupplyAt} with the snapshot id.
* To get the balance of an account from a snapshot, call the `balanceOfAt` function with the snapshot id and the * To get the balance of an account from a snapshot, call the {balanceOfAt} function with the snapshot id and the
* account address. * account address.
* @author Validity Labs AG <info@validitylabs.org> * @author Validity Labs AG <info@validitylabs.org>
*/ */
......
= Drafts
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
== ERC 20
{{ERC20Migrator}}
{{ERC20Snapshot}}
{{TokenVesting}}
== Miscellaneous
{{Counters}}
{{SignedSafeMath}}
== ERC 1046
{{ERC1046}}
---
sections:
- title: ERC 20
contracts:
- ERC20Migrator
- ERC20Snapshot
- TokenVesting
- title: Miscellenous
contracts:
- Counters
- SignatureBouncer
- SignedSafeMath
- subdirectory: ERC1046
---
> This page is incomplete. We're working to improve it for the next release. Stay tuned!
pragma solidity ^0.5.0;
import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "../GSN/Context.sol";
import "../access/roles/SignerRole.sol";
import "../cryptography/ECDSA.sol";
/**
* @title SignatureBouncer
* @author PhABC, Shrugs and aflesher
* @dev SignatureBouncer allows users to submit a signature as a permission to
* do an action.
* If the signature is from one of the authorized signer addresses, the
* signature is valid.
* Note that SignatureBouncer offers no protection against replay attacks, users
* must add this themselves!
*
* Signer addresses can be individual servers signing grants or different
* users within a decentralized club that have permission to invite other
* members. This technique is useful for whitelists and airdrops; instead of
* putting all valid addresses on-chain, simply sign a grant of the form
* keccak256(abi.encodePacked(`:contractAddress` + `:granteeAddress`)) using a
* valid signer address.
* Then restrict access to your crowdsale/whitelist/airdrop using the
* `onlyValidSignature` modifier (or implement your own using _isValidSignature).
* In addition to `onlyValidSignature`, `onlyValidSignatureAndMethod` and
* `onlyValidSignatureAndData` can be used to restrict access to only a given
* method or a given method with given parameters respectively.
* See the tests in SignatureBouncer.test.js for specific usage examples.
*
* @notice A method that uses the `onlyValidSignatureAndData` modifier must make
* the _signature parameter the "last" parameter. You cannot sign a message that
* has its own signature in it so the last 128 bytes of msg.data (which
* represents the length of the _signature data and the _signature data itself)
* is ignored when validating. Also non fixed sized parameters make constructing
* the data in the signature much more complex.
* See https://ethereum.stackexchange.com/a/50616 for more details.
*/
contract SignatureBouncer is Initializable, Context, SignerRole {
using ECDSA for bytes32;
// Function selectors are 4 bytes long, as documented in
// https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector
uint256 private constant _METHOD_ID_SIZE = 4;
// Signature size is 65 bytes (tightly packed v + r + s), but gets padded to 96 bytes
uint256 private constant _SIGNATURE_SIZE = 96;
function initialize(address sender) public initializer {
SignerRole.initialize(sender);
}
/**
* @dev Requires that a valid signature of a signer was provided.
*/
modifier onlyValidSignature(bytes memory signature) {
require(_isValidSignature(_msgSender(), signature), "SignatureBouncer: invalid signature for caller");
_;
}
/**
* @dev Requires that a valid signature with a specified method of a signer was provided.
*/
modifier onlyValidSignatureAndMethod(bytes memory signature) {
// solhint-disable-next-line max-line-length
require(_isValidSignatureAndMethod(_msgSender(), signature), "SignatureBouncer: invalid signature for caller and method");
_;
}
/**
* @dev Requires that a valid signature with a specified method and params of a signer was provided.
*/
modifier onlyValidSignatureAndData(bytes memory signature) {
// solhint-disable-next-line max-line-length
require(_isValidSignatureAndData(_msgSender(), signature), "SignatureBouncer: invalid signature for caller and data");
_;
}
/**
* @dev is the signature of `this + account` from a signer?
* @return bool
*/
function _isValidSignature(address account, bytes memory signature) internal view returns (bool) {
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account)), signature);
}
/**
* @dev is the signature of `this + account + methodId` from a signer?
* @return bool
*/
function _isValidSignatureAndMethod(address account, bytes memory signature) internal view returns (bool) {
bytes memory msgData = _msgData();
bytes memory data = new bytes(_METHOD_ID_SIZE);
for (uint256 i = 0; i < data.length; i++) {
data[i] = msgData[i];
}
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account, data)), signature);
}
/**
* @dev is the signature of `this + account + methodId + params(s)` from a signer?
* @notice the signature parameter of the method being validated must be the "last" parameter
* @return bool
*/
function _isValidSignatureAndData(address account, bytes memory signature) internal view returns (bool) {
bytes memory msgData = _msgData();
require(msgData.length > _SIGNATURE_SIZE, "SignatureBouncer: data is too short");
bytes memory data = new bytes(msgData.length - _SIGNATURE_SIZE);
for (uint256 i = 0; i < data.length; i++) {
data[i] = msgData[i];
}
return _isValidDataHash(keccak256(abi.encodePacked(address(this), account, data)), signature);
}
/**
* @dev Internal function to convert a hash to an eth signed message
* and then recover the signature and check it against the signer role.
* @return bool
*/
function _isValidDataHash(bytes32 hash, bytes memory signature) internal view returns (bool) {
address signer = hash.toEthSignedMessageHash().recover(signature);
return signer != address(0) && isSigner(signer);
}
uint256[50] private ______gap;
}
...@@ -13,7 +13,7 @@ library SignedSafeMath { ...@@ -13,7 +13,7 @@ library SignedSafeMath {
function mul(int256 a, int256 b) internal pure returns (int256) { function mul(int256 a, int256 b) internal pure returns (int256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested. // benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) { if (a == 0) {
return 0; return 0;
} }
......
pragma solidity ^0.5.0;
/**
* @title Strings
* @dev String operations.
*/
library Strings {
/**
* @dev Converts a `uint256` to a `string`.
* via OraclizeAPI - MIT licence
* https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
*/
function fromUint256(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
uint256 index = digits - 1;
temp = value;
while (temp != 0) {
buffer[index--] = byte(uint8(48 + temp % 10));
temp /= 10;
}
return string(buffer);
}
}
...@@ -4,9 +4,9 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol"; ...@@ -4,9 +4,9 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./IERC165.sol"; import "./IERC165.sol";
/** /**
* @dev Implementation of the `IERC165` interface. * @dev Implementation of the {IERC165} interface.
* *
* Contracts may inherit from this and call `_registerInterface` to declare * Contracts may inherit from this and call {_registerInterface} to declare
* their support of an interface. * their support of an interface.
*/ */
contract ERC165 is Initializable, IERC165 { contract ERC165 is Initializable, IERC165 {
...@@ -27,7 +27,7 @@ contract ERC165 is Initializable, IERC165 { ...@@ -27,7 +27,7 @@ contract ERC165 is Initializable, IERC165 {
} }
/** /**
* @dev See `IERC165.supportsInterface`. * @dev See {IERC165-supportsInterface}.
* *
* Time complexity O(1), guaranteed to always use less than 30 000 gas. * Time complexity O(1), guaranteed to always use less than 30 000 gas.
*/ */
...@@ -40,7 +40,7 @@ contract ERC165 is Initializable, IERC165 { ...@@ -40,7 +40,7 @@ contract ERC165 is Initializable, IERC165 {
* `interfaceId`. Support of the actual ERC165 interface is automatic and * `interfaceId`. Support of the actual ERC165 interface is automatic and
* registering its interface id is not required. * registering its interface id is not required.
* *
* See `IERC165.supportsInterface`. * See {IERC165-supportsInterface}.
* *
* Requirements: * Requirements:
* *
......
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
/** /**
* @dev Library used to query support of an interface declared via `IERC165`. * @dev Library used to query support of an interface declared via {IERC165}.
* *
* Note that these functions return the actual result of the query: they do not * Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide * `revert` if an interface is not supported. It is up to the caller to decide
...@@ -17,7 +17,7 @@ library ERC165Checker { ...@@ -17,7 +17,7 @@ library ERC165Checker {
bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
/** /**
* @dev Returns true if `account` supports the `IERC165` interface, * @dev Returns true if `account` supports the {IERC165} interface,
*/ */
function _supportsERC165(address account) internal view returns (bool) { function _supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of // Any contract that implements ERC165 must explicitly indicate support of
...@@ -28,9 +28,9 @@ library ERC165Checker { ...@@ -28,9 +28,9 @@ library ERC165Checker {
/** /**
* @dev Returns true if `account` supports the interface defined by * @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for `IERC165` itself is queried automatically. * `interfaceId`. Support for {IERC165} itself is queried automatically.
* *
* See `IERC165.supportsInterface`. * See {IERC165-supportsInterface}.
*/ */
function _supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { function _supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId // query support of both ERC165 as per the spec and support of _interfaceId
...@@ -40,12 +40,12 @@ library ERC165Checker { ...@@ -40,12 +40,12 @@ library ERC165Checker {
/** /**
* @dev Returns true if `account` supports all the interfaces defined in * @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for `IERC165` itself is queried automatically. * `interfaceIds`. Support for {IERC165} itself is queried automatically.
* *
* Batch-querying can lead to gas savings by skipping repeated checks for * Batch-querying can lead to gas savings by skipping repeated checks for
* `IERC165` support. * {IERC165} support.
* *
* See `IERC165.supportsInterface`. * See {IERC165-supportsInterface}.
*/ */
function _supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { function _supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself // query support of ERC165 itself
......
...@@ -3,11 +3,11 @@ pragma solidity ^0.5.0; ...@@ -3,11 +3,11 @@ pragma solidity ^0.5.0;
import "./IERC1820Implementer.sol"; import "./IERC1820Implementer.sol";
/** /**
* @dev Implementation of the `IERC1820Implementer` interface. * @dev Implementation of the {IERC1820Implementer} interface.
* *
* Contracts may inherit from this and call `_registerInterfaceForAddress` to * Contracts may inherit from this and call {_registerInterfaceForAddress} to
* declare their willingness to be implementers. * declare their willingness to be implementers.
* `IERC1820Registry.setInterfaceImplementer` should then be called for the * {IERC1820Registry-setInterfaceImplementer} should then be called for the
* registration to be complete. * registration to be complete.
*/ */
contract ERC1820Implementer is IERC1820Implementer { contract ERC1820Implementer is IERC1820Implementer {
...@@ -16,7 +16,7 @@ contract ERC1820Implementer is IERC1820Implementer { ...@@ -16,7 +16,7 @@ contract ERC1820Implementer is IERC1820Implementer {
mapping(bytes32 => mapping(address => bool)) private _supportedInterfaces; mapping(bytes32 => mapping(address => bool)) private _supportedInterfaces;
/** /**
* See `IERC1820Implementer.canImplementInterfaceForAddress`. * See {IERC1820Implementer-canImplementInterfaceForAddress}.
*/ */
function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32) { function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32) {
return _supportedInterfaces[interfaceHash][account] ? ERC1820_ACCEPT_MAGIC : bytes32(0x00); return _supportedInterfaces[interfaceHash][account] ? ERC1820_ACCEPT_MAGIC : bytes32(0x00);
...@@ -26,8 +26,8 @@ contract ERC1820Implementer is IERC1820Implementer { ...@@ -26,8 +26,8 @@ contract ERC1820Implementer is IERC1820Implementer {
* @dev Declares the contract as willing to be an implementer of * @dev Declares the contract as willing to be an implementer of
* `interfaceHash` for `account`. * `interfaceHash` for `account`.
* *
* See `IERC1820Registry.setInterfaceImplementer` and * See {IERC1820Registry-setInterfaceImplementer} and
* `IERC1820Registry.interfaceHash`. * {IERC1820Registry-interfaceHash}.
*/ */
function _registerInterfaceForAddress(bytes32 interfaceHash, address account) internal { function _registerInterfaceForAddress(bytes32 interfaceHash, address account) internal {
_supportedInterfaces[interfaceHash][account] = true; _supportedInterfaces[interfaceHash][account] = true;
......
...@@ -2,18 +2,18 @@ pragma solidity ^0.5.0; ...@@ -2,18 +2,18 @@ pragma solidity ^0.5.0;
/** /**
* @dev Interface of the ERC165 standard, as defined in the * @dev Interface of the ERC165 standard, as defined in the
* [EIP](https://eips.ethereum.org/EIPS/eip-165). * https://eips.ethereum.org/EIPS/eip-165[EIP].
* *
* Implementers can declare support of contract interfaces, which can then be * Implementers can declare support of contract interfaces, which can then be
* queried by others (`ERC165Checker`). * queried by others ({ERC165Checker}).
* *
* For an implementation, see `ERC165`. * For an implementation, see {ERC165}.
*/ */
interface IERC165 { interface IERC165 {
/** /**
* @dev Returns true if this contract implements the interface defined by * @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding * `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created. * to learn more about how these ids are created.
* *
* This function call must use less than 30 000 gas. * This function call must use less than 30 000 gas.
......
...@@ -2,16 +2,16 @@ pragma solidity ^0.5.0; ...@@ -2,16 +2,16 @@ pragma solidity ^0.5.0;
/** /**
* @dev Interface for an ERC1820 implementer, as defined in the * @dev Interface for an ERC1820 implementer, as defined in the
* [EIP](https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface). * https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[EIP].
* Used by contracts that will be registered as implementers in the * Used by contracts that will be registered as implementers in the
* `IERC1820Registry`. * {IERC1820Registry}.
*/ */
interface IERC1820Implementer { interface IERC1820Implementer {
/** /**
* @dev Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract * @dev Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract
* implements `interfaceHash` for `account`. * implements `interfaceHash` for `account`.
* *
* See `IERC1820Registry.setInterfaceImplementer`. * See {IERC1820Registry-setInterfaceImplementer}.
*/ */
function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32); function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32);
} }
...@@ -2,7 +2,7 @@ pragma solidity ^0.5.0; ...@@ -2,7 +2,7 @@ pragma solidity ^0.5.0;
/** /**
* @dev Interface of the global ERC1820 Registry, as defined in the * @dev Interface of the global ERC1820 Registry, as defined in the
* [EIP](https://eips.ethereum.org/EIPS/eip-1820). Accounts may register * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register
* implementers for interfaces in this registry, as well as query support. * implementers for interfaces in this registry, as well as query support.
* *
* Implementers may be shared by multiple accounts, and can also implement more * Implementers may be shared by multiple accounts, and can also implement more
...@@ -10,7 +10,7 @@ pragma solidity ^0.5.0; ...@@ -10,7 +10,7 @@ pragma solidity ^0.5.0;
* for themselves, but externally-owned accounts (EOA) must delegate this to a * for themselves, but externally-owned accounts (EOA) must delegate this to a
* contract. * contract.
* *
* `IERC165` interfaces can also be queried via the registry. * {IERC165} interfaces can also be queried via the registry.
* *
* For an in-depth explanation and source code analysis, see the EIP text. * For an in-depth explanation and source code analysis, see the EIP text.
*/ */
...@@ -22,7 +22,7 @@ interface IERC1820Registry { ...@@ -22,7 +22,7 @@ interface IERC1820Registry {
* By default, each account is its own manager. Passing a value of `0x0` in * By default, each account is its own manager. Passing a value of `0x0` in
* `newManager` will reset the manager to this initial state. * `newManager` will reset the manager to this initial state.
* *
* Emits a `ManagerChanged` event. * Emits a {ManagerChanged} event.
* *
* Requirements: * Requirements:
* *
...@@ -33,7 +33,7 @@ interface IERC1820Registry { ...@@ -33,7 +33,7 @@ interface IERC1820Registry {
/** /**
* @dev Returns the manager for `account`. * @dev Returns the manager for `account`.
* *
* See `setManager`. * See {setManager}.
*/ */
function getManager(address account) external view returns (address); function getManager(address account) external view returns (address);
...@@ -44,18 +44,18 @@ interface IERC1820Registry { ...@@ -44,18 +44,18 @@ interface IERC1820Registry {
* `account` being the zero address is an alias for the caller's address. * `account` being the zero address is an alias for the caller's address.
* The zero address can also be used in `implementer` to remove an old one. * The zero address can also be used in `implementer` to remove an old one.
* *
* See `interfaceHash` to learn how these are created. * See {interfaceHash} to learn how these are created.
* *
* Emits an `InterfaceImplementerSet` event. * Emits an {InterfaceImplementerSet} event.
* *
* Requirements: * Requirements:
* *
* - the caller must be the current manager for `account`. * - the caller must be the current manager for `account`.
* - `interfaceHash` must not be an `IERC165` interface id (i.e. it must not * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not
* end in 28 zeroes). * end in 28 zeroes).
* - `implementer` must implement `IERC1820Implementer` and return true when * - `implementer` must implement {IERC1820Implementer} and return true when
* queried for support, unless `implementer` is the caller. See * queried for support, unless `implementer` is the caller. See
* `IERC1820Implementer.canImplementInterfaceForAddress`. * {IERC1820Implementer-canImplementInterfaceForAddress}.
*/ */
function setInterfaceImplementer(address account, bytes32 interfaceHash, address implementer) external; function setInterfaceImplementer(address account, bytes32 interfaceHash, address implementer) external;
...@@ -63,7 +63,7 @@ interface IERC1820Registry { ...@@ -63,7 +63,7 @@ interface IERC1820Registry {
* @dev Returns the implementer of `interfaceHash` for `account`. If no such * @dev Returns the implementer of `interfaceHash` for `account`. If no such
* implementer is registered, returns the zero address. * implementer is registered, returns the zero address.
* *
* If `interfaceHash` is an `IERC165` interface id (i.e. it ends with 28 * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28
* zeroes), `account` will be queried for support of it. * zeroes), `account` will be queried for support of it.
* *
* `account` being the zero address is an alias for the caller's address. * `account` being the zero address is an alias for the caller's address.
...@@ -73,7 +73,7 @@ interface IERC1820Registry { ...@@ -73,7 +73,7 @@ interface IERC1820Registry {
/** /**
* @dev Returns the interface hash for an `interfaceName`, as defined in the * @dev Returns the interface hash for an `interfaceName`, as defined in the
* corresponding * corresponding
* [section of the EIP](https://eips.ethereum.org/EIPS/eip-1820#interface-name). * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].
*/ */
function interfaceHash(string calldata interfaceName) external pure returns (bytes32); function interfaceHash(string calldata interfaceName) external pure returns (bytes32);
...@@ -88,10 +88,10 @@ interface IERC1820Registry { ...@@ -88,10 +88,10 @@ interface IERC1820Registry {
* @notice Checks whether a contract implements an ERC165 interface or not. * @notice Checks whether a contract implements an ERC165 interface or not.
* If the result is not cached a direct lookup on the contract address is performed. * If the result is not cached a direct lookup on the contract address is performed.
* If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling
* 'updateERC165Cache' with the contract address. * {updateERC165Cache} with the contract address.
* @param account Address of the contract to check. * @param account Address of the contract to check.
* @param interfaceId ERC165 interface to check. * @param interfaceId ERC165 interface to check.
* @return True if `account.address()` implements `interfaceId`, false otherwise. * @return True if `account` implements `interfaceId`, false otherwise.
*/ */
function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);
...@@ -99,7 +99,7 @@ interface IERC1820Registry { ...@@ -99,7 +99,7 @@ interface IERC1820Registry {
* @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.
* @param account Address of the contract to check. * @param account Address of the contract to check.
* @param interfaceId ERC165 interface to check. * @param interfaceId ERC165 interface to check.
* @return True if `account.address()` implements `interfaceId`, false otherwise. * @return True if `account` implements `interfaceId`, false otherwise.
*/ */
function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);
......
--- = Introspection
sections:
- title: Local
contracts:
- IERC165
- ERC165
- ERC165Checker
- title: Global
contracts:
- IERC1820Registry
- IERC1820Implementer
- ERC1820Implementer
---
This set of interfaces and contracts deal with [type introspection](https://en.wikipedia.org/wiki/Type_introspection) of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_. This set of interfaces and contracts deal with [type introspection](https://en.wikipedia.org/wiki/Type_introspection) of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_.
Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors. Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors.
There are two main ways to approach this. There are two main ways to approach this.
- Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`.
- Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts. * Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`.
* Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts.
Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security. Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security.
== Local
{{IERC165}}
{{ERC165}}
{{ERC165Checker}}
== Global
{{IERC1820Registry}}
{{IERC1820Implementer}}
{{ERC1820Implementer}}
= Math
These are math-related utilities.
== Libraries
{{SafeMath}}
{{Math}}
---
title: Math
sections:
- title: Libraries
contracts:
- SafeMath
- Math
---
These are math-related utilities.
...@@ -40,7 +40,22 @@ library SafeMath { ...@@ -40,7 +40,22 @@ library SafeMath {
* - Subtraction cannot overflow. * - Subtraction cannot overflow.
*/ */
function sub(uint256 a, uint256 b) internal pure returns (uint256) { function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow"); return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b; uint256 c = a - b;
return c; return c;
...@@ -58,7 +73,7 @@ library SafeMath { ...@@ -58,7 +73,7 @@ library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) { function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested. // benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) { if (a == 0) {
return 0; return 0;
} }
...@@ -81,8 +96,25 @@ library SafeMath { ...@@ -81,8 +96,25 @@ library SafeMath {
* - The divisor cannot be zero. * - The divisor cannot be zero.
*/ */
function div(uint256 a, uint256 b) internal pure returns (uint256) { function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0 // Solidity only automatically asserts when dividing by 0
require(b > 0, "SafeMath: division by zero"); require(b > 0, errorMessage);
uint256 c = a / b; uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold // assert(a == b * c + a % b); // There is no case in which this doesn't hold
...@@ -101,7 +133,24 @@ library SafeMath { ...@@ -101,7 +133,24 @@ library SafeMath {
* - The divisor cannot be zero. * - The divisor cannot be zero.
*/ */
function mod(uint256 a, uint256 b) internal pure returns (uint256) { function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: modulo by zero"); return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b; return a % b;
} }
} }
...@@ -6,4 +6,14 @@ contract AddressImpl { ...@@ -6,4 +6,14 @@ contract AddressImpl {
function isContract(address account) external view returns (bool) { function isContract(address account) external view returns (bool) {
return Address.isContract(account); return Address.isContract(account);
} }
function toPayable(address account) external pure returns (address payable) {
return Address.toPayable(account);
}
function sendValue(address payable receiver, uint256 amount) external {
Address.sendValue(receiver, amount);
}
function () external payable { } // sendValue's tests require the contract to hold Ether
} }
...@@ -5,8 +5,7 @@ import "./PauserRoleMock.sol"; ...@@ -5,8 +5,7 @@ import "./PauserRoleMock.sol";
// mock class using ERC20Pausable // mock class using ERC20Pausable
contract ERC20PausableMock is ERC20Pausable, PauserRoleMock { contract ERC20PausableMock is ERC20Pausable, PauserRoleMock {
constructor (address initialAccount, uint initialBalance) public { constructor (address initialAccount, uint256 initialBalance) public {
ERC20Pausable.initialize(_msgSender());
_mint(initialAccount, initialBalance); _mint(initialAccount, initialBalance);
} }
} }
pragma solidity ^0.5.2; pragma solidity ^0.5.0;
import "../token/ERC721/ERC721.sol"; import "../token/ERC721/ERC721.sol";
import "../GSN/GSNRecipient.sol"; import "../GSN/GSNRecipient.sol";
import "../GSN/bouncers/GSNBouncerSignature.sol"; import "../GSN/GSNRecipientSignature.sol";
/** /**
* @title ERC721GSNRecipientMock * @title ERC721GSNRecipientMock
* A simple ERC721 mock that has GSN support enabled * A simple ERC721 mock that has GSN support enabled
*/ */
contract ERC721GSNRecipientMock is ERC721, GSNRecipient, GSNBouncerSignature { contract ERC721GSNRecipientMock is ERC721, GSNRecipient, GSNRecipientSignature {
constructor(address trustedSigner) public { constructor(address trustedSigner) public {
ERC721.initialize(); ERC721.initialize();
GSNRecipient.initialize(); GSNRecipient.initialize();
GSNBouncerSignature.initialize(trustedSigner); GSNRecipientSignature.initialize(trustedSigner);
} }
function mint(uint256 tokenId) public { function mint(uint256 tokenId) public {
......
...@@ -4,13 +4,21 @@ import "../token/ERC721/ERC721.sol"; ...@@ -4,13 +4,21 @@ import "../token/ERC721/ERC721.sol";
/** /**
* @title ERC721Mock * @title ERC721Mock
* This mock just provides a public mint and burn functions for testing purposes * This mock just provides a public safeMint, mint, and burn functions for testing purposes
*/ */
contract ERC721Mock is ERC721 { contract ERC721Mock is ERC721 {
constructor() public { constructor() public {
ERC721.initialize(); ERC721.initialize();
} }
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function mint(address to, uint256 tokenId) public { function mint(address to, uint256 tokenId) public {
_mint(to, tokenId); _mint(to, tokenId);
} }
......
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
import "../GSN/Context.sol";
import "../token/ERC777/ERC777.sol"; import "../token/ERC777/ERC777.sol";
contract ERC777Mock is ERC777 { contract ERC777Mock is Context, ERC777 {
constructor( constructor(
address initialHolder, address initialHolder,
uint256 initialBalance, uint256 initialBalance,
......
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
import "../GSN/Context.sol";
import "../token/ERC777/IERC777.sol"; import "../token/ERC777/IERC777.sol";
import "../token/ERC777/IERC777Sender.sol"; import "../token/ERC777/IERC777Sender.sol";
import "../token/ERC777/IERC777Recipient.sol"; import "../token/ERC777/IERC777Recipient.sol";
import "../introspection/IERC1820Registry.sol"; import "../introspection/IERC1820Registry.sol";
import "../introspection/ERC1820Implementer.sol"; import "../introspection/ERC1820Implementer.sol";
contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Implementer { contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer {
event TokensToSendCalled( event TokensToSendCalled(
address operator, address operator,
address from, address from,
...@@ -43,7 +44,7 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im ...@@ -43,7 +44,7 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im
address operator, address operator,
address from, address from,
address to, address to,
uint amount, uint256 amount,
bytes calldata userData, bytes calldata userData,
bytes calldata operatorData bytes calldata operatorData
) external { ) external {
...@@ -51,7 +52,7 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im ...@@ -51,7 +52,7 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im
revert(); revert();
} }
IERC777 token = IERC777(msg.sender); IERC777 token = IERC777(_msgSender());
uint256 fromBalance = token.balanceOf(from); uint256 fromBalance = token.balanceOf(from);
// when called due to burn, to will be the zero address, which will have a balance of 0 // when called due to burn, to will be the zero address, which will have a balance of 0
...@@ -74,7 +75,7 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im ...@@ -74,7 +75,7 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im
address operator, address operator,
address from, address from,
address to, address to,
uint amount, uint256 amount,
bytes calldata userData, bytes calldata userData,
bytes calldata operatorData bytes calldata operatorData
) external{ ) external{
...@@ -82,7 +83,7 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im ...@@ -82,7 +83,7 @@ contract ERC777SenderRecipientMock is IERC777Sender, IERC777Recipient, ERC1820Im
revert(); revert();
} }
IERC777 token = IERC777(msg.sender); IERC777 token = IERC777(_msgSender());
uint256 fromBalance = token.balanceOf(from); uint256 fromBalance = token.balanceOf(from);
// when called due to burn, to will be the zero address, which will have a balance of 0 // when called due to burn, to will be the zero address, which will have a balance of 0
......
pragma solidity ^0.5.0;
contract EtherReceiverMock {
bool private _acceptEther;
function setAcceptEther(bool acceptEther) public {
_acceptEther = acceptEther;
}
function () external payable {
if (!_acceptEther) {
revert();
}
}
}
pragma solidity ^0.5.0;
import "./ContextMock.sol";
import "../GSN/GSNContext.sol";
import "../GSN/IRelayRecipient.sol";
// By inheriting from GSNContext, Context's internal functions are overridden automatically
contract GSNContextMock is ContextMock, GSNContext, IRelayRecipient {
constructor() public {
GSNContext.initialize();
}
function getHubAddr() public view returns (address) {
return _getRelayHub();
}
function acceptRelayedCall(
address,
address,
bytes calldata,
uint256,
uint256,
uint256,
uint256,
bytes calldata,
uint256
)
external
view
returns (uint256, bytes memory)
{
return (0, "");
}
function preRelayedCall(bytes calldata) external returns (bytes32) {
// solhint-disable-previous-line no-empty-blocks
}
function postRelayedCall(bytes calldata, bool, uint256, bytes32) external {
// solhint-disable-previous-line no-empty-blocks
}
function getRelayHub() public view returns (address) {
return _getRelayHub();
}
function upgradeRelayHub(address newRelayHub) public {
return _upgradeRelayHub(newRelayHub);
}
}
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "../GSN/GSNRecipient.sol"; import "../GSN/GSNRecipient.sol";
import "../GSN/bouncers/GSNBouncerERC20Fee.sol"; import "../GSN/GSNRecipientERC20Fee.sol";
contract GSNBouncerERC20FeeMock is GSNRecipient, GSNBouncerERC20Fee { contract GSNRecipientERC20FeeMock is GSNRecipient, GSNRecipientERC20Fee {
constructor(string memory name, string memory symbol, uint8 decimals) public { constructor(string memory name, string memory symbol) public {
GSNRecipient.initialize(); GSNRecipientERC20Fee.initialize(name, symbol);
GSNBouncerERC20Fee.initialize(name, symbol, decimals);
} }
function mint(address account, uint256 amount) public { function mint(address account, uint256 amount) public {
......
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
import "./ContextMock.sol";
import "../GSN/GSNRecipient.sol"; import "../GSN/GSNRecipient.sol";
contract GSNRecipientMock is GSNRecipient { // By inheriting from GSNRecipient, Context's internal functions are overridden automatically
contract GSNRecipientMock is ContextMock, GSNRecipient {
constructor() public { constructor() public {
GSNRecipient.initialize(); GSNRecipient.initialize();
} }
...@@ -19,11 +21,15 @@ contract GSNRecipientMock is GSNRecipient { ...@@ -19,11 +21,15 @@ contract GSNRecipientMock is GSNRecipient {
return (0, ""); return (0, "");
} }
function preRelayedCall(bytes calldata) external returns (bytes32) { function _preRelayedCall(bytes memory) internal returns (bytes32) {
// solhint-disable-previous-line no-empty-blocks // solhint-disable-previous-line no-empty-blocks
} }
function postRelayedCall(bytes calldata, bool, uint256, bytes32) external { function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal {
// solhint-disable-previous-line no-empty-blocks // solhint-disable-previous-line no-empty-blocks
} }
function upgradeRelayHub(address newRelayHub) public {
return _upgradeRelayHub(newRelayHub);
}
} }
pragma solidity ^0.5.0; pragma solidity ^0.5.0;
import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "../GSN/GSNRecipient.sol"; import "../GSN/GSNRecipient.sol";
import "../GSN/bouncers/GSNBouncerSignature.sol"; import "../GSN/GSNRecipientSignature.sol";
contract GSNBouncerSignatureMock is GSNRecipient, GSNBouncerSignature { contract GSNRecipientSignatureMock is GSNRecipient, GSNRecipientSignature {
constructor(address trustedSigner) public { constructor(address trustedSigner) public {
GSNRecipient.initialize(); GSNRecipientSignature.initialize(trustedSigner);
GSNBouncerSignature.initialize(trustedSigner);
} }
event MockFunctionCalled(); event MockFunctionCalled();
......
pragma solidity ^0.5.0;
import "../drafts/SignatureBouncer.sol";
import "./SignerRoleMock.sol";
contract SignatureBouncerMock is SignatureBouncer, SignerRoleMock {
constructor() public {
SignatureBouncer.initialize(_msgSender());
}
function checkValidSignature(address account, bytes memory signature)
public view returns (bool)
{
return _isValidSignature(account, signature);
}
function onlyWithValidSignature(bytes memory signature)
public onlyValidSignature(signature) view
{
// solhint-disable-previous-line no-empty-blocks
}
function checkValidSignatureAndMethod(address account, bytes memory signature)
public view returns (bool)
{
return _isValidSignatureAndMethod(account, signature);
}
function onlyWithValidSignatureAndMethod(bytes memory signature)
public onlyValidSignatureAndMethod(signature) view
{
// solhint-disable-previous-line no-empty-blocks
}
function checkValidSignatureAndData(address account, bytes memory, uint, bytes memory signature)
public view returns (bool)
{
return _isValidSignatureAndData(account, signature);
}
function onlyWithValidSignatureAndData(uint, bytes memory signature)
public onlyValidSignatureAndData(signature) view
{
// solhint-disable-previous-line no-empty-blocks
}
function theWrongMethod(bytes memory) public pure {
// solhint-disable-previous-line no-empty-blocks
}
function tooShortMsgData() public onlyValidSignatureAndData("") view {
// solhint-disable-previous-line no-empty-blocks
}
}
pragma solidity ^0.5.0;
import "../drafts/Strings.sol";
contract StringsMock {
function fromUint256(uint256 value) public pure returns (string memory) {
return Strings.fromUint256(value);
}
}
= Ownership
Contract modules for simple authorization and access control mechanisms.
TIP: For more complex needs see xref:access.adoc.
== Contracts
{{Ownable}}
{{Secondary}}
Contract modules for simple authorization and access control mechanisms.
For more complex needs see [Access](access).
{
"name": "@openzeppelin/contracts",
"version": "2.4.0",
"description": "Secure Smart Contract library for Solidity",
"files": [
"**/*.sol",
"/build/contracts/*.json",
"!/mocks",
"!/examples"
],
"scripts": {
"prepare": "bash ../scripts/prepare-contracts-package.sh"
},
"repository": {
"type": "git",
"url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git"
},
"keywords": [
"solidity",
"ethereum",
"smart",
"contracts",
"security",
"zeppelin"
],
"author": "OpenZeppelin Community <maintainers@openzeppelin.org>",
"license": "MIT",
"bugs": {
"url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues"
},
"homepage": "https://github.com/OpenZeppelin/openzeppelin-contracts"
}
...@@ -15,7 +15,7 @@ import "../math/SafeMath.sol"; ...@@ -15,7 +15,7 @@ import "../math/SafeMath.sol";
* an amount proportional to the percentage of total shares they were assigned. * an amount proportional to the percentage of total shares they were assigned.
* *
* `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the
* accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the `release` * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release}
* function. * function.
*/ */
contract PaymentSplitter is Initializable, Context { contract PaymentSplitter is Initializable, Context {
...@@ -50,13 +50,13 @@ contract PaymentSplitter is Initializable, Context { ...@@ -50,13 +50,13 @@ contract PaymentSplitter is Initializable, Context {
} }
/** /**
* @dev The Ether received will be logged with `PaymentReceived` events. Note that these events are not fully * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully
* reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the
* reliability of the events, and not the actual splitting of Ether. * reliability of the events, and not the actual splitting of Ether.
* *
* To learn more about this see the Solidity documentation for [fallback functions]. * To learn more about this see the Solidity documentation for
* * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback
* [fallback functions]: https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function * functions].
*/ */
function () external payable { function () external payable {
emit PaymentReceived(_msgSender(), msg.value); emit PaymentReceived(_msgSender(), msg.value);
......
...@@ -5,9 +5,18 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol"; ...@@ -5,9 +5,18 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./escrow/Escrow.sol"; import "./escrow/Escrow.sol";
/** /**
* @title PullPayment * @dev Simple implementation of a
* @dev Base contract supporting async send for pull payments. Inherit from this * https://consensys.github.io/smart-contract-best-practices/recommendations/#favor-pull-over-push-for-external-calls[pull-payment]
* contract and use _asyncTransfer instead of send or transfer. * strategy, where the paying contract doesn't interact directly with the
* receiver account, which must withdraw its payments itself.
*
* Pull-payments are often considered the best practice when it comes to sending
* Ether, security-wise. It prevents recipients from blocking execution, and
* eliminates reentrancy concerns.
*
* To use, derive from the `PullPayment` contract, and use {_asyncTransfer}
* instead of Solidity's `transfer` function. Payees can query their due
* payments with {payments}, and retrieve them with {withdrawPayments}.
*/ */
contract PullPayment is Initializable { contract PullPayment is Initializable {
Escrow private _escrow; Escrow private _escrow;
...@@ -21,15 +30,39 @@ contract PullPayment is Initializable { ...@@ -21,15 +30,39 @@ contract PullPayment is Initializable {
} }
/** /**
* @dev Withdraw accumulated balance. * @dev Withdraw accumulated payments.
* @param payee Whose balance will be withdrawn. *
* Note that _any_ account can call this function, not just the `payee`.
* This means that contracts unaware of the `PullPayment` protocol can still
* receive funds this way, by having a separate account call
* {withdrawPayments}.
*
* NOTE: This function has been deprecated, use {withdrawPaymentsWithGas}
* instead. Calling contracts with fixed gas limits is an anti-pattern and
* may break contract interactions in network upgrades (hardforks).
* https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more.]
*
* @param payee Whose payments will be withdrawn.
*/ */
function withdrawPayments(address payable payee) public { function withdrawPayments(address payable payee) public {
_escrow.withdraw(payee); _escrow.withdraw(payee);
} }
/** /**
* @dev Returns the credit owed to an address. * @dev Same as {withdrawPayments}, but forwarding all gas to the recipient.
*
* WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
* Make sure you trust the recipient, or are either following the
* checks-effects-interactions pattern or using {ReentrancyGuard}.
*
* _Available since v2.4.0._
*/
function withdrawPaymentsWithGas(address payable payee) external {
_escrow.withdrawWithGas(payee);
}
/**
* @dev Returns the payments owed to an address.
* @param dest The creditor's address. * @param dest The creditor's address.
*/ */
function payments(address dest) public view returns (uint256) { function payments(address dest) public view returns (uint256) {
...@@ -38,6 +71,9 @@ contract PullPayment is Initializable { ...@@ -38,6 +71,9 @@ contract PullPayment is Initializable {
/** /**
* @dev Called by the payer to store the sent amount as credit to be pulled. * @dev Called by the payer to store the sent amount as credit to be pulled.
* Funds sent in this way are stored in an intermediate {Escrow} contract, so
* there is no danger of them being spent before withdrawal.
*
* @param dest The destination address of the funds. * @param dest The destination address of the funds.
* @param amount The amount to transfer. * @param amount The amount to transfer.
*/ */
......
= Payment
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
== Utilities
{{PaymentSplitter}}
{{PullPayment}}
== Escrow
{{Escrow}}
{{ConditionalEscrow}}
{{RefundEscrow}}
---
sections:
- title: Payment Utilities
contracts:
- PaymentSplitter
- PullPayment
- subdirectory: escrow
---
> This page is incomplete. We're working to improve it for the next release. Stay tuned!
...@@ -5,7 +5,7 @@ import "./Escrow.sol"; ...@@ -5,7 +5,7 @@ import "./Escrow.sol";
/** /**
* @title ConditionalEscrow * @title ConditionalEscrow
* @dev Base abstract escrow to only allow withdrawal if a condition is met. * @dev Base abstract escrow to only allow withdrawal if a condition is met.
* @dev Intended usage: See Escrow.sol. Same usage guidelines apply here. * @dev Intended usage: See {Escrow}. Same usage guidelines apply here.
*/ */
contract ConditionalEscrow is Initializable, Escrow { contract ConditionalEscrow is Initializable, Escrow {
function initialize(address sender) public initializer { function initialize(address sender) public initializer {
......
...@@ -2,21 +2,24 @@ pragma solidity ^0.5.0; ...@@ -2,21 +2,24 @@ pragma solidity ^0.5.0;
import "../../math/SafeMath.sol"; import "../../math/SafeMath.sol";
import "../../ownership/Secondary.sol"; import "../../ownership/Secondary.sol";
import "../../utils/Address.sol";
/** /**
* @title Escrow * @title Escrow
* @dev Base escrow contract, holds funds designated for a payee until they * @dev Base escrow contract, holds funds designated for a payee until they
* withdraw them. * withdraw them.
* @dev Intended usage: This contract (and derived escrow contracts) should be a *
* Intended usage: This contract (and derived escrow contracts) should be a
* standalone contract, that only interacts with the contract that instantiated * standalone contract, that only interacts with the contract that instantiated
* it. That way, it is guaranteed that all Ether will be handled according to * it. That way, it is guaranteed that all Ether will be handled according to
* the Escrow rules, and there is no need to check for payable functions or * the `Escrow` rules, and there is no need to check for payable functions or
* transfers in the inheritance tree. The contract that uses the escrow as its * transfers in the inheritance tree. The contract that uses the escrow as its
* payment method should be its primary, and provide public methods redirecting * payment method should be its primary, and provide public methods redirecting
* to the escrow's deposit and withdraw. * to the escrow's deposit and withdraw.
*/ */
contract Escrow is Initializable, Secondary { contract Escrow is Initializable, Secondary {
using SafeMath for uint256; using SafeMath for uint256;
using Address for address payable;
event Deposited(address indexed payee, uint256 weiAmount); event Deposited(address indexed payee, uint256 weiAmount);
event Withdrawn(address indexed payee, uint256 weiAmount); event Withdrawn(address indexed payee, uint256 weiAmount);
...@@ -43,7 +46,14 @@ contract Escrow is Initializable, Secondary { ...@@ -43,7 +46,14 @@ contract Escrow is Initializable, Secondary {
} }
/** /**
* @dev Withdraw accumulated balance for a payee. * @dev Withdraw accumulated balance for a payee, forwarding 2300 gas (a
* Solidity `transfer`).
*
* NOTE: This function has been deprecated, use {withdrawWithGas} instead.
* Calling contracts with fixed-gas limits is an anti-pattern and may break
* contract interactions in network upgrades (hardforks).
* https://diligence.consensys.net/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more.]
*
* @param payee The address whose funds will be withdrawn and transferred to. * @param payee The address whose funds will be withdrawn and transferred to.
*/ */
function withdraw(address payable payee) public onlyPrimary { function withdraw(address payable payee) public onlyPrimary {
...@@ -56,5 +66,24 @@ contract Escrow is Initializable, Secondary { ...@@ -56,5 +66,24 @@ contract Escrow is Initializable, Secondary {
emit Withdrawn(payee, payment); emit Withdrawn(payee, payment);
} }
/**
* @dev Same as {withdraw}, but forwarding all gas to the recipient.
*
* WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
* Make sure you trust the recipient, or are either following the
* checks-effects-interactions pattern or using {ReentrancyGuard}.
*
* _Available since v2.4.0._
*/
function withdrawWithGas(address payable payee) public onlyPrimary {
uint256 payment = _deposits[payee];
_deposits[payee] = 0;
payee.sendValue(payment);
emit Withdrawn(payee, payment);
}
uint256[50] private ______gap; uint256[50] private ______gap;
} }
---
title: Escrows
sections:
- contracts:
- Escrow
- ConditionalEscrow
- RefundEscrow
---
...@@ -8,12 +8,12 @@ import "./ConditionalEscrow.sol"; ...@@ -8,12 +8,12 @@ import "./ConditionalEscrow.sol";
* @title RefundEscrow * @title RefundEscrow
* @dev Escrow that holds funds for a beneficiary, deposited from multiple * @dev Escrow that holds funds for a beneficiary, deposited from multiple
* parties. * parties.
* @dev Intended usage: See Escrow.sol. Same usage guidelines apply here. * @dev Intended usage: See {Escrow}. Same usage guidelines apply here.
* @dev The primary account (that is, the contract that instantiates this * @dev The primary account (that is, the contract that instantiates this
* contract) may deposit, close the deposit period, and allow for either * contract) may deposit, close the deposit period, and allow for either
* withdrawal by the beneficiary, or refunds to the depositors. All interactions * withdrawal by the beneficiary, or refunds to the depositors. All interactions
* with RefundEscrow will be made through the primary contract. See the * with `RefundEscrow` will be made through the primary contract. See the
* RefundableCrowdsale contract for an example of RefundEscrow’s use. * `RefundableCrowdsale` contract for an example of `RefundEscrow`’s use.
*/ */
contract RefundEscrow is Initializable, ConditionalEscrow { contract RefundEscrow is Initializable, ConditionalEscrow {
enum State { Active, Refunding, Closed } enum State { Active, Refunding, Closed }
......
...@@ -6,22 +6,22 @@ import "../../GSN/Context.sol"; ...@@ -6,22 +6,22 @@ import "../../GSN/Context.sol";
import "./ERC20.sol"; import "./ERC20.sol";
/** /**
* @dev Extension of `ERC20` that allows token holders to destroy both their own * @dev Extension of {ERC20} that allows token holders to destroy both their own
* tokens and those that they have an allowance for, in a way that can be * tokens and those that they have an allowance for, in a way that can be
* recognized off-chain (via event analysis). * recognized off-chain (via event analysis).
*/ */
contract ERC20Burnable is Initializable, Context, ERC20 { contract ERC20Burnable is Initializable, Context, ERC20 {
/** /**
* @dev Destoys `amount` tokens from the caller. * @dev Destroys `amount` tokens from the caller.
* *
* See `ERC20._burn`. * See {ERC20-_burn}.
*/ */
function burn(uint256 amount) public { function burn(uint256 amount) public {
_burn(_msgSender(), amount); _burn(_msgSender(), amount);
} }
/** /**
* @dev See `ERC20._burnFrom`. * @dev See {ERC20-_burnFrom}.
*/ */
function burnFrom(address account, uint256 amount) public { function burnFrom(address account, uint256 amount) public {
_burnFrom(account, amount); _burnFrom(account, amount);
......
...@@ -4,7 +4,7 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol"; ...@@ -4,7 +4,7 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./ERC20Mintable.sol"; import "./ERC20Mintable.sol";
/** /**
* @dev Extension of `ERC20Mintable` that adds a cap to the supply of tokens. * @dev Extension of {ERC20Mintable} that adds a cap to the supply of tokens.
*/ */
contract ERC20Capped is Initializable, ERC20Mintable { contract ERC20Capped is Initializable, ERC20Mintable {
uint256 private _cap; uint256 private _cap;
...@@ -28,7 +28,7 @@ contract ERC20Capped is Initializable, ERC20Mintable { ...@@ -28,7 +28,7 @@ contract ERC20Capped is Initializable, ERC20Mintable {
} }
/** /**
* @dev See `ERC20Mintable.mint`. * @dev See {ERC20Mintable-mint}.
* *
* Requirements: * Requirements:
* *
......
...@@ -45,9 +45,9 @@ contract ERC20Detailed is Initializable, IERC20 { ...@@ -45,9 +45,9 @@ contract ERC20Detailed is Initializable, IERC20 {
* Tokens usually opt for a value of 18, imitating the relationship between * Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. * Ether and Wei.
* *
* > Note that this information is only used for _display_ purposes: it in * NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including * no way affects any of the arithmetic of the contract, including
* `IERC20.balanceOf` and `IERC20.transfer`. * {IERC20-balanceOf} and {IERC20-transfer}.
*/ */
function decimals() public view returns (uint8) { function decimals() public view returns (uint8) {
return _decimals; return _decimals;
......
...@@ -5,7 +5,7 @@ import "./ERC20.sol"; ...@@ -5,7 +5,7 @@ import "./ERC20.sol";
import "../../access/roles/MinterRole.sol"; import "../../access/roles/MinterRole.sol";
/** /**
* @dev Extension of `ERC20` that adds a set of accounts with the `MinterRole`, * @dev Extension of {ERC20} that adds a set of accounts with the {MinterRole},
* which have permission to mint (create) new tokens as they see fit. * which have permission to mint (create) new tokens as they see fit.
* *
* At construction, the deployer of the contract is the only minter. * At construction, the deployer of the contract is the only minter.
...@@ -16,11 +16,11 @@ contract ERC20Mintable is Initializable, ERC20, MinterRole { ...@@ -16,11 +16,11 @@ contract ERC20Mintable is Initializable, ERC20, MinterRole {
} }
/** /**
* @dev See `ERC20._mint`. * @dev See {ERC20-_mint}.
* *
* Requirements: * Requirements:
* *
* - the caller must have the `MinterRole`. * - the caller must have the {MinterRole}.
*/ */
function mint(address account, uint256 amount) public onlyMinter returns (bool) { function mint(address account, uint256 amount) public onlyMinter returns (bool) {
_mint(account, amount); _mint(account, amount);
......
...@@ -6,7 +6,11 @@ import "../../lifecycle/Pausable.sol"; ...@@ -6,7 +6,11 @@ import "../../lifecycle/Pausable.sol";
/** /**
* @title Pausable token * @title Pausable token
* @dev ERC20 modified with pausable transfers. * @dev ERC20 with pausable transfers and allowances.
*
* Useful if you want to stop trades until the end of a crowdsale, or have
* an emergency switch for freezing all token transfers in the event of a large
* bug.
*/ */
contract ERC20Pausable is Initializable, ERC20, Pausable { contract ERC20Pausable is Initializable, ERC20, Pausable {
function initialize(address sender) public initializer { function initialize(address sender) public initializer {
...@@ -25,11 +29,11 @@ contract ERC20Pausable is Initializable, ERC20, Pausable { ...@@ -25,11 +29,11 @@ contract ERC20Pausable is Initializable, ERC20, Pausable {
return super.approve(spender, value); return super.approve(spender, value);
} }
function increaseAllowance(address spender, uint addedValue) public whenNotPaused returns (bool) { function increaseAllowance(address spender, uint256 addedValue) public whenNotPaused returns (bool) {
return super.increaseAllowance(spender, addedValue); return super.increaseAllowance(spender, addedValue);
} }
function decreaseAllowance(address spender, uint subtractedValue) public whenNotPaused returns (bool) { function decreaseAllowance(address spender, uint256 subtractedValue) public whenNotPaused returns (bool) {
return super.decreaseAllowance(spender, subtractedValue); return super.decreaseAllowance(spender, subtractedValue);
} }
......
...@@ -2,7 +2,7 @@ pragma solidity ^0.5.0; ...@@ -2,7 +2,7 @@ pragma solidity ^0.5.0;
/** /**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`. * the optional functions; to access them see {ERC20Detailed}.
*/ */
interface IERC20 { interface IERC20 {
/** /**
...@@ -20,16 +20,16 @@ interface IERC20 { ...@@ -20,16 +20,16 @@ interface IERC20 {
* *
* Returns a boolean value indicating whether the operation succeeded. * Returns a boolean value indicating whether the operation succeeded.
* *
* Emits a `Transfer` event. * Emits a {Transfer} event.
*/ */
function transfer(address recipient, uint256 amount) external returns (bool); function transfer(address recipient, uint256 amount) external returns (bool);
/** /**
* @dev Returns the remaining number of tokens that `spender` will be * @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through `transferFrom`. This is * allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default. * zero by default.
* *
* This value changes when `approve` or `transferFrom` are called. * This value changes when {approve} or {transferFrom} are called.
*/ */
function allowance(address owner, address spender) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256);
...@@ -38,14 +38,14 @@ interface IERC20 { ...@@ -38,14 +38,14 @@ interface IERC20 {
* *
* Returns a boolean value indicating whether the operation succeeded. * Returns a boolean value indicating whether the operation succeeded.
* *
* > Beware that changing an allowance with this method brings the risk * IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate * that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race * transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the * condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards: * desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* *
* Emits an `Approval` event. * Emits an {Approval} event.
*/ */
function approve(address spender, uint256 amount) external returns (bool); function approve(address spender, uint256 amount) external returns (bool);
...@@ -56,7 +56,7 @@ interface IERC20 { ...@@ -56,7 +56,7 @@ interface IERC20 {
* *
* Returns a boolean value indicating whether the operation succeeded. * Returns a boolean value indicating whether the operation succeeded.
* *
* Emits a `Transfer` event. * Emits a {Transfer} event.
*/ */
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
...@@ -70,7 +70,7 @@ interface IERC20 { ...@@ -70,7 +70,7 @@ interface IERC20 {
/** /**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by * @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to `approve`. `value` is the new allowance. * a call to {approve}. `value` is the new allowance.
*/ */
event Approval(address indexed owner, address indexed spender, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value);
} }
= ERC 20
This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-20[ERC20 Token Standard].
TIP: For an overview of ERC20 tokens and a walkthrough on how to create a token contract read our xref:ROOT:tokens.adoc#ERC20[ERC20 guide].
There a few core contracts that implement the behavior specified in the EIP:
* {IERC20}: the interface all ERC20 implementations should conform to
* {ERC20}: the base implementation of the ERC20 interface
* {ERC20Detailed}: includes the <<ERC20Detailed-name,`name`>>,
<<ERC20Detailed-symbol,`symbol`>> and <<ERC20Detailed-decimals,`decimals`>>
optional standard extension to the base interface
Additionally there are multiple custom extensions, including:
* designation of addresses that can create token supply ({ERC20Mintable}), with an optional maximum cap ({ERC20Capped})
* destruction of own tokens ({ERC20Burnable})
* designation of addresses that can pause token operations for all users ({ERC20Pausable}).
Finally, there are some utilities to interact with ERC20 contracts in various ways.
* {SafeERC20} is a wrapper around the interface that eliminates the need to handle boolean return values.
* {TokenTimelock} can hold tokens for a beneficiary until a specified time.
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
== Core
{{IERC20}}
{{ERC20}}
{{ERC20Detailed}}
== Extensions
{{ERC20Mintable}}
{{ERC20Burnable}}
{{ERC20Pausable}}
{{ERC20Capped}}
== Utilities
{{SafeERC20}}
{{TokenTimelock}}
---
sections:
- title: Core
contracts:
- IERC20
- ERC20
- ERC20Detailed
- title: Extensions
contracts:
- ERC20Mintable
- ERC20Burnable
- ERC20Pausable
- ERC20Capped
- title: Utilities
contracts:
- SafeERC20
- TokenTimelock
---
This set of interfaces, contracts, and utilities are all related to the [ERC20 Token Standard](https://eips.ethereum.org/EIPS/eip-20).
*For a walkthrough on how to create an ERC20 token read our [ERC20 guide](../../tokens.md#constructing-a-nice-erc20-token).*
There a few core contracts that implement the behavior specified in the EIP: `IERC20`, `ERC20`, `ERC20Detailed`.
Additionally there are multiple extensions, including:
- designation of addresses that can create token supply (`ERC20Mintable`), with an optional maximum cap (`ERC20Capped`),
- destruction of own tokens (`ERC20Burnable`),
- designation of addresses that can pause token operations for all users (`ERC20Pausable`).
Finally, there are some utilities to interact with ERC20 contracts in various ways.
- `SafeERC20` is a wrapper around the interface that eliminates the need to handle boolean return values.
- `TokenTimelock` can hold tokens for a beneficiary until a specified time.
> This page is incomplete. We're working to improve it for the next release. Stay tuned!
...@@ -42,7 +42,7 @@ library SafeERC20 { ...@@ -42,7 +42,7 @@ library SafeERC20 {
} }
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value); uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
} }
......
...@@ -4,9 +4,13 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol"; ...@@ -4,9 +4,13 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol";
import "./SafeERC20.sol"; import "./SafeERC20.sol";
/** /**
* @title TokenTimelock * @dev A token holder contract that will allow a beneficiary to extract the
* @dev TokenTimelock is a token holder contract that will allow a * tokens after a given release time.
* beneficiary to extract the tokens after a given release time. *
* Useful for simple vesting schedules like "advisors get all of their tokens
* after 1 year".
*
* For a more complete vesting schedule, see {TokenVesting}.
*/ */
contract TokenTimelock is Initializable { contract TokenTimelock is Initializable {
using SafeERC20 for IERC20; using SafeERC20 for IERC20;
......
...@@ -41,7 +41,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -41,7 +41,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
* bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
* bytes4(keccak256('getApproved(uint256)')) == 0x081812fc * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
* bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
* bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
* bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
* bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
...@@ -142,7 +142,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -142,7 +142,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
/** /**
* @dev Transfers the ownership of a given token ID to another address. * @dev Transfers the ownership of a given token ID to another address.
* Usage of this method is discouraged, use `safeTransferFrom` whenever possible. * Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
* Requires the msg.sender to be the owner, approved, or operator. * Requires the msg.sender to be the owner, approved, or operator.
* @param from current owner of the token * @param from current owner of the token
* @param to address to receive the ownership of the given token ID * @param to address to receive the ownership of the given token ID
...@@ -157,7 +157,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -157,7 +157,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
/** /**
* @dev Safely transfers the ownership of a given token ID to another address * @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`, * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
* which is called upon a safe transfer, and return the magic value * which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted. * the transfer is reverted.
...@@ -172,7 +172,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -172,7 +172,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
/** /**
* @dev Safely transfers the ownership of a given token ID to another address * @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`, * If the target address is a contract, it must implement {IERC721Receiver-onERC721Received},
* which is called upon a safe transfer, and return the magic value * which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted. * the transfer is reverted.
...@@ -183,7 +183,24 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -183,7 +183,24 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
* @param _data bytes data to send along with a safe transfer check * @param _data bytes data to send along with a safe transfer check
*/ */
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
transferFrom(from, to, tokenId); require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransferFrom(from, to, tokenId, _data);
}
/**
* @dev Safely transfers the ownership of a given token ID to another address
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* Requires the _msgSender() to be the owner, approved, or operator
* @param from current owner of the token
* @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred
* @param _data bytes data to send along with a safe transfer check
*/
function _safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) internal {
_transferFrom(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
} }
...@@ -211,6 +228,36 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -211,6 +228,36 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
} }
/** /**
* @dev Internal function to safely mint a new token.
* Reverts if the given token ID already exists.
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted
*/
function _safeMint(address to, uint256 tokenId) internal {
_safeMint(to, tokenId, "");
}
/**
* @dev Internal function to safely mint a new token.
* Reverts if the given token ID already exists.
* If the target address is a contract, it must implement `onERC721Received`,
* which is called upon a safe transfer, and return the magic value
* `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
* the transfer is reverted.
* @param to The address that will own the minted token
* @param tokenId uint256 ID of the token to be minted
* @param _data bytes data to send along with a safe transfer check
*/
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal {
_mint(to, tokenId);
require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
/**
* @dev Internal function to mint a new token. * @dev Internal function to mint a new token.
* Reverts if the given token ID already exists. * Reverts if the given token ID already exists.
* @param to The address that will own the minted token * @param to The address that will own the minted token
...@@ -229,7 +276,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -229,7 +276,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
/** /**
* @dev Internal function to burn a specific token. * @dev Internal function to burn a specific token.
* Reverts if the token does not exist. * Reverts if the token does not exist.
* Deprecated, use _burn(uint256) instead. * Deprecated, use {_burn} instead.
* @param owner owner of the token to burn * @param owner owner of the token to burn
* @param tokenId uint256 ID of the token being burned * @param tokenId uint256 ID of the token being burned
*/ */
...@@ -255,7 +302,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -255,7 +302,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
/** /**
* @dev Internal function to transfer ownership of a given token ID to another address. * @dev Internal function to transfer ownership of a given token ID to another address.
* As opposed to transferFrom, this imposes no restrictions on msg.sender. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
* @param from current owner of the token * @param from current owner of the token
* @param to address to receive the ownership of the given token ID * @param to address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to be transferred * @param tokenId uint256 ID of the token to be transferred
...@@ -275,7 +322,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 { ...@@ -275,7 +322,7 @@ contract ERC721 is Initializable, Context, ERC165, IERC721 {
} }
/** /**
* @dev Internal function to invoke `onERC721Received` on a target address. * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
* The call is not executed if the target address is not a contract. * The call is not executed if the target address is not a contract.
* *
* This function is deprecated. * This function is deprecated.
......
...@@ -108,7 +108,7 @@ contract ERC721Enumerable is Initializable, Context, ERC165, ERC721, IERC721Enum ...@@ -108,7 +108,7 @@ contract ERC721Enumerable is Initializable, Context, ERC165, ERC721, IERC721Enum
/** /**
* @dev Internal function to burn a specific token. * @dev Internal function to burn a specific token.
* Reverts if the token does not exist. * Reverts if the token does not exist.
* Deprecated, use _burn(uint256) instead. * Deprecated, use {ERC721-_burn} instead.
* @param owner owner of the token to burn * @param owner owner of the token to burn
* @param tokenId uint256 ID of the token being burned * @param tokenId uint256 ID of the token being burned
*/ */
...@@ -152,7 +152,7 @@ contract ERC721Enumerable is Initializable, Context, ERC165, ERC721, IERC721Enum ...@@ -152,7 +152,7 @@ contract ERC721Enumerable is Initializable, Context, ERC165, ERC721, IERC721Enum
/** /**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the _ownedTokensIndex mapping is _not_ updated: this allows for * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes). * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array. * This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID * @param from address representing the previous owner of the given token ID
......
...@@ -7,9 +7,10 @@ import "./ERC721Metadata.sol"; ...@@ -7,9 +7,10 @@ import "./ERC721Metadata.sol";
/** /**
* @title Full ERC721 Token * @title Full ERC721 Token
* This implementation includes all the required and some optional functionality of the ERC721 standard * @dev This implementation includes all the required and some optional functionality of the ERC721 standard
* Moreover, it includes approve all functionality using operator terminology * Moreover, it includes approve all functionality using operator terminology.
* @dev see https://eips.ethereum.org/EIPS/eip-721 *
* See https://eips.ethereum.org/EIPS/eip-721
*/ */
contract ERC721Full is Initializable, ERC721, ERC721Enumerable, ERC721Metadata { contract ERC721Full is Initializable, ERC721, ERC721Enumerable, ERC721Metadata {
uint256[50] private ______gap; uint256[50] private ______gap;
......
...@@ -16,7 +16,7 @@ contract ERC721Mintable is Initializable, ERC721, MinterRole { ...@@ -16,7 +16,7 @@ contract ERC721Mintable is Initializable, ERC721, MinterRole {
/** /**
* @dev Function to mint tokens. * @dev Function to mint tokens.
* @param to The address that will receive the minted tokens. * @param to The address that will receive the minted token.
* @param tokenId The token id to mint. * @param tokenId The token id to mint.
* @return A boolean that indicates if the operation was successful. * @return A boolean that indicates if the operation was successful.
*/ */
...@@ -25,5 +25,28 @@ contract ERC721Mintable is Initializable, ERC721, MinterRole { ...@@ -25,5 +25,28 @@ contract ERC721Mintable is Initializable, ERC721, MinterRole {
return true; return true;
} }
/**
* @dev Function to safely mint tokens.
* @param to The address that will receive the minted token.
* @param tokenId The token id to mint.
* @return A boolean that indicates if the operation was successful.
*/
function safeMint(address to, uint256 tokenId) public onlyMinter returns (bool) {
_safeMint(to, tokenId);
return true;
}
/**
* @dev Function to safely mint tokens.
* @param to The address that will receive the minted token.
* @param tokenId The token id to mint.
* @param _data bytes data to send along with a safe transfer check.
* @return A boolean that indicates if the operation was successful.
*/
function safeMint(address to, uint256 tokenId, bytes memory _data) public onlyMinter returns (bool) {
_safeMint(to, tokenId, _data);
return true;
}
uint256[50] private ______gap; uint256[50] private ______gap;
} }
...@@ -22,8 +22,8 @@ contract ERC721Pausable is Initializable, ERC721, Pausable { ...@@ -22,8 +22,8 @@ contract ERC721Pausable is Initializable, ERC721, Pausable {
super.setApprovalForAll(to, approved); super.setApprovalForAll(to, approved);
} }
function transferFrom(address from, address to, uint256 tokenId) public whenNotPaused { function _transferFrom(address from, address to, uint256 tokenId) internal whenNotPaused {
super.transferFrom(from, to, tokenId); super._transferFrom(from, to, tokenId);
} }
uint256[50] private ______gap; uint256[50] private ______gap;
......
...@@ -25,13 +25,13 @@ contract IERC721 is Initializable, IERC165 { ...@@ -25,13 +25,13 @@ contract IERC721 is Initializable, IERC165 {
* @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to
* another (`to`). * another (`to`).
* *
* *
* *
* Requirements: * Requirements:
* - `from`, `to` cannot be zero. * - `from`, `to` cannot be zero.
* - `tokenId` must be owned by `from`. * - `tokenId` must be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this * - If the caller is not `from`, it must be have been allowed to move this
* NFT by either `approve` or `setApproveForAll`. * NFT by either {approve} or {setApprovalForAll}.
*/ */
function safeTransferFrom(address from, address to, uint256 tokenId) public; function safeTransferFrom(address from, address to, uint256 tokenId) public;
/** /**
...@@ -40,7 +40,7 @@ contract IERC721 is Initializable, IERC165 { ...@@ -40,7 +40,7 @@ contract IERC721 is Initializable, IERC165 {
* *
* Requirements: * Requirements:
* - If the caller is not `from`, it must be approved to move this NFT by * - If the caller is not `from`, it must be approved to move this NFT by
* either `approve` or `setApproveForAll`. * either {approve} or {setApprovalForAll}.
*/ */
function transferFrom(address from, address to, uint256 tokenId) public; function transferFrom(address from, address to, uint256 tokenId) public;
function approve(address to, uint256 tokenId) public; function approve(address to, uint256 tokenId) public;
......
...@@ -9,7 +9,7 @@ contract IERC721Receiver { ...@@ -9,7 +9,7 @@ contract IERC721Receiver {
/** /**
* @notice Handle the receipt of an NFT * @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient * @dev The ERC721 smart contract calls this function on the recipient
* after a `safeTransfer`. This function MUST return the function selector, * after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be * otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as `this.onERC721Received.selector`. This * returned can be obtained as `this.onERC721Received.selector`. This
* function MAY throw to revert and reject the transfer. * function MAY throw to revert and reject the transfer.
......
= ERC 721
This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-721[ERC721 Non-Fungible Token Standard].
TIP: For a walkthrough on how to create an ERC721 token read our xref:ROOT:tokens.adoc#ERC721[ERC721 guide].
The EIP consists of three interfaces, found here as {IERC721}, {IERC721Metadata}, and {IERC721Enumerable}. Only the first one is required in a contract to be ERC721 compliant.
Each interface is implemented separately in {ERC721}, {ERC721Metadata}, and {ERC721Enumerable}. You can choose the subset of functionality you would like to support in your token by combining the
desired subset through inheritance.
The fully featured token implementing all three interfaces is prepackaged as {ERC721Full}.
Additionally, {IERC721Receiver} can be used to prevent tokens from becoming forever locked in contracts. Imagine sending an in-game item to an exchange address that can't send it back!. When using <<IERC721-safeTransferFrom,`safeTransferFrom`>>, the token contract checks to see that the receiver is an {IERC721Receiver}, which implies that it knows how to handle {ERC721} tokens. If you're writing a contract that needs to receive {ERC721} tokens, you'll want to include this interface.
Finally, some custom extensions are also included:
* {ERC721Mintable} — like the ERC20 version, this allows certain addresses to mint new tokens
* {ERC721Pausable} — like the ERC20 version, this allows addresses to freeze transfers of tokens
NOTE: This page is incomplete. We're working to improve it for the next release. Stay tuned!
== Core
{{IERC721}}
{{ERC721}}
{{IERC721Metadata}}
{{ERC721Metadata}}
{{ERC721Enumerable}}
{{IERC721Enumerable}}
{{IERC721Full}}
{{ERC721Full}}
{{IERC721Receiver}}
== Extensions
{{ERC721Mintable}}
{{ERC721MetadataMintable}}
{{ERC721Burnable}}
{{ERC721Pausable}}
== Convenience
{{ERC721Holder}}
---
sections:
- title: Core
contracts:
- IERC721
- ERC721
- IERC721Metadata
- ERC721Metadata
- ERC721Enumerable
- IERC721Enumerable
- IERC721Full
- ERC721Full
- IERC721Receiver
- title: Extensions
contracts:
- ERC721Mintable
- ERC721MetadataMintable
- ERC721Burnable
- ERC721Pausable
- title: Convenience
contracts:
- ERC721Holder
---
This set of interfaces, contracts, and utilities are all related to the [ERC721 Non-Fungible Token Standard](https://eips.ethereum.org/EIPS/eip-721).
*For a walkthrough on how to create an ERC721 token read our [ERC721 guide](../../tokens.md#erc721).*
The EIP consists of three interfaces, found here as `IERC721`,
`IERC721Metadata`, and `IERC721Enumerable`. Only the first one is required in a
contract to be ERC721 compliant. Each interface is implemented separately in
`ERC721`, `ERC721Metadata`, and `ERC721Enumerable`. You can choose the subset
of functionality you would like to support in your token by combining the
desired subset through inheritance. The fully featured token implementing all
three interfaces is prepackaged as `ERC721Full`.
> This page is incomplete. We're working to improve it for the next release. Stay tuned!
...@@ -4,10 +4,10 @@ pragma solidity ^0.5.0; ...@@ -4,10 +4,10 @@ pragma solidity ^0.5.0;
* @dev Interface of the ERC777Token standard as defined in the EIP. * @dev Interface of the ERC777Token standard as defined in the EIP.
* *
* This contract uses the * This contract uses the
* [ERC1820 registry standard](https://eips.ethereum.org/EIPS/eip-1820) to let * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let
* token holders and recipients react to token movements by using setting implementers * token holders and recipients react to token movements by using setting implementers
* for the associated interfaces in said registry. See `IERC1820Registry` and * for the associated interfaces in said registry. See {IERC1820Registry} and
* `ERC1820Implementer`. * {ERC1820Implementer}.
*/ */
interface IERC777 { interface IERC777 {
/** /**
...@@ -45,15 +45,15 @@ interface IERC777 { ...@@ -45,15 +45,15 @@ interface IERC777 {
* *
* If send or receive hooks are registered for the caller and `recipient`, * If send or receive hooks are registered for the caller and `recipient`,
* the corresponding functions will be called with `data` and empty * the corresponding functions will be called with `data` and empty
* `operatorData`. See `IERC777Sender` and `IERC777Recipient`. * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
* *
* Emits a `Sent` event. * Emits a {Sent} event.
* *
* Requirements * Requirements
* *
* - the caller must have at least `amount` tokens. * - the caller must have at least `amount` tokens.
* - `recipient` cannot be the zero address. * - `recipient` cannot be the zero address.
* - if `recipient` is a contract, it must implement the `tokensReceived` * - if `recipient` is a contract, it must implement the {IERC777Recipient}
* interface. * interface.
*/ */
function send(address recipient, uint256 amount, bytes calldata data) external; function send(address recipient, uint256 amount, bytes calldata data) external;
...@@ -63,9 +63,9 @@ interface IERC777 { ...@@ -63,9 +63,9 @@ interface IERC777 {
* total supply. * total supply.
* *
* If a send hook is registered for the caller, the corresponding function * If a send hook is registered for the caller, the corresponding function
* will be called with `data` and empty `operatorData`. See `IERC777Sender`. * will be called with `data` and empty `operatorData`. See {IERC777Sender}.
* *
* Emits a `Burned` event. * Emits a {Burned} event.
* *
* Requirements * Requirements
* *
...@@ -78,16 +78,16 @@ interface IERC777 { ...@@ -78,16 +78,16 @@ interface IERC777 {
* Operators can send and burn tokens on behalf of their owners. All * Operators can send and burn tokens on behalf of their owners. All
* accounts are their own operator. * accounts are their own operator.
* *
* See `operatorSend` and `operatorBurn`. * See {operatorSend} and {operatorBurn}.
*/ */
function isOperatorFor(address operator, address tokenHolder) external view returns (bool); function isOperatorFor(address operator, address tokenHolder) external view returns (bool);
/** /**
* @dev Make an account an operator of the caller. * @dev Make an account an operator of the caller.
* *
* See `isOperatorFor`. * See {isOperatorFor}.
* *
* Emits an `AuthorizedOperator` event. * Emits an {AuthorizedOperator} event.
* *
* Requirements * Requirements
* *
...@@ -98,9 +98,9 @@ interface IERC777 { ...@@ -98,9 +98,9 @@ interface IERC777 {
/** /**
* @dev Make an account an operator of the caller. * @dev Make an account an operator of the caller.
* *
* See `isOperatorFor` and `defaultOperators`. * See {isOperatorFor} and {defaultOperators}.
* *
* Emits a `RevokedOperator` event. * Emits a {RevokedOperator} event.
* *
* Requirements * Requirements
* *
...@@ -110,11 +110,11 @@ interface IERC777 { ...@@ -110,11 +110,11 @@ interface IERC777 {
/** /**
* @dev Returns the list of default operators. These accounts are operators * @dev Returns the list of default operators. These accounts are operators
* for all token holders, even if `authorizeOperator` was never called on * for all token holders, even if {authorizeOperator} was never called on
* them. * them.
* *
* This list is immutable, but individual holders may revoke these via * This list is immutable, but individual holders may revoke these via
* `revokeOperator`, in which case `isOperatorFor` will return false. * {revokeOperator}, in which case {isOperatorFor} will return false.
*/ */
function defaultOperators() external view returns (address[] memory); function defaultOperators() external view returns (address[] memory);
...@@ -124,9 +124,9 @@ interface IERC777 { ...@@ -124,9 +124,9 @@ interface IERC777 {
* *
* If send or receive hooks are registered for `sender` and `recipient`, * If send or receive hooks are registered for `sender` and `recipient`,
* the corresponding functions will be called with `data` and * the corresponding functions will be called with `data` and
* `operatorData`. See `IERC777Sender` and `IERC777Recipient`. * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.
* *
* Emits a `Sent` event. * Emits a {Sent} event.
* *
* Requirements * Requirements
* *
...@@ -134,7 +134,7 @@ interface IERC777 { ...@@ -134,7 +134,7 @@ interface IERC777 {
* - `sender` must have at least `amount` tokens. * - `sender` must have at least `amount` tokens.
* - the caller must be an operator for `sender`. * - the caller must be an operator for `sender`.
* - `recipient` cannot be the zero address. * - `recipient` cannot be the zero address.
* - if `recipient` is a contract, it must implement the `tokensReceived` * - if `recipient` is a contract, it must implement the {IERC777Recipient}
* interface. * interface.
*/ */
function operatorSend( function operatorSend(
...@@ -150,9 +150,9 @@ interface IERC777 { ...@@ -150,9 +150,9 @@ interface IERC777 {
* The caller must be an operator of `account`. * The caller must be an operator of `account`.
* *
* If a send hook is registered for `account`, the corresponding function * If a send hook is registered for `account`, the corresponding function
* will be called with `data` and `operatorData`. See `IERC777Sender`. * will be called with `data` and `operatorData`. See {IERC777Sender}.
* *
* Emits a `Burned` event. * Emits a {Burned} event.
* *
* Requirements * Requirements
* *
......
...@@ -3,21 +3,21 @@ pragma solidity ^0.5.0; ...@@ -3,21 +3,21 @@ pragma solidity ^0.5.0;
/** /**
* @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.
* *
* Accounts can be notified of `IERC777` tokens being sent to them by having a * Accounts can be notified of {IERC777} tokens being sent to them by having a
* contract implement this interface (contract holders can be their own * contract implement this interface (contract holders can be their own
* implementer) and registering it on the * implementer) and registering it on the
* [ERC1820 global registry](https://eips.ethereum.org/EIPS/eip-1820). * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].
* *
* See `IERC1820Registry` and `ERC1820Implementer`. * See {IERC1820Registry} and {ERC1820Implementer}.
*/ */
interface IERC777Recipient { interface IERC777Recipient {
/** /**
* @dev Called by an `IERC777` token contract whenever tokens are being * @dev Called by an {IERC777} token contract whenever tokens are being
* moved or created into a registered account (`to`). The type of operation * moved or created into a registered account (`to`). The type of operation
* is conveyed by `from` being the zero address or not. * is conveyed by `from` being the zero address or not.
* *
* This call occurs _after_ the token contract's state is updated, so * This call occurs _after_ the token contract's state is updated, so
* `IERC777.balanceOf`, etc., can be used to query the post-operation state. * {IERC777-balanceOf}, etc., can be used to query the post-operation state.
* *
* This function may revert to prevent the operation from being executed. * This function may revert to prevent the operation from being executed.
*/ */
...@@ -25,7 +25,7 @@ interface IERC777Recipient { ...@@ -25,7 +25,7 @@ interface IERC777Recipient {
address operator, address operator,
address from, address from,
address to, address to,
uint amount, uint256 amount,
bytes calldata userData, bytes calldata userData,
bytes calldata operatorData bytes calldata operatorData
) external; ) external;
......
...@@ -3,21 +3,21 @@ pragma solidity ^0.5.0; ...@@ -3,21 +3,21 @@ pragma solidity ^0.5.0;
/** /**
* @dev Interface of the ERC777TokensSender standard as defined in the EIP. * @dev Interface of the ERC777TokensSender standard as defined in the EIP.
* *
* `IERC777` Token holders can be notified of operations performed on their * {IERC777} Token holders can be notified of operations performed on their
* tokens by having a contract implement this interface (contract holders can be * tokens by having a contract implement this interface (contract holders can be
* their own implementer) and registering it on the * their own implementer) and registering it on the
* [ERC1820 global registry](https://eips.ethereum.org/EIPS/eip-1820). * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].
* *
* See `IERC1820Registry` and `ERC1820Implementer`. * See {IERC1820Registry} and {ERC1820Implementer}.
*/ */
interface IERC777Sender { interface IERC777Sender {
/** /**
* @dev Called by an `IERC777` token contract whenever a registered holder's * @dev Called by an {IERC777} token contract whenever a registered holder's
* (`from`) tokens are about to be moved or destroyed. The type of operation * (`from`) tokens are about to be moved or destroyed. The type of operation
* is conveyed by `to` being the zero address or not. * is conveyed by `to` being the zero address or not.
* *
* This call occurs _before_ the token contract's state is updated, so * This call occurs _before_ the token contract's state is updated, so
* `IERC777.balanceOf`, etc., can be used to query the pre-operation state. * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.
* *
* This function may revert to prevent the operation from being executed. * This function may revert to prevent the operation from being executed.
*/ */
...@@ -25,7 +25,7 @@ interface IERC777Sender { ...@@ -25,7 +25,7 @@ interface IERC777Sender {
address operator, address operator,
address from, address from,
address to, address to,
uint amount, uint256 amount,
bytes calldata userData, bytes calldata userData,
bytes calldata operatorData bytes calldata operatorData
) external; ) external;
......
= ERC 777
This set of interfaces and contracts are all related to the [ERC777 token standard](https://eips.ethereum.org/EIPS/eip-777).
TIP: For an overview of ERC777 tokens and a walkthrough on how to create a token contract read our xref:ROOT:tokens.adoc#ERC777[ERC777 guide].
The token behavior itself is implemented in the core contracts: {IERC777}, {ERC777}.
Additionally there are interfaces used to develop contracts that react to token movements: {IERC777Sender}, {IERC777Recipient}.
== Core
{{IERC777}}
{{ERC777}}
== Hooks
{{IERC777Sender}}
{{IERC777Recipient}}
---
sections:
- title: Core
contracts:
- IERC777
- ERC777
- title: Hooks
contracts:
- IERC777Sender
- IERC777Recipient
---
This set of interfaces and contracts are all related to the [ERC777 token standard](https://eips.ethereum.org/EIPS/eip-777).
The token behavior itself is implemented in the core contracts: `IERC777`, `ERC777`.
Additionally there are interfaces used to develop contracts that react to token movements: `IERC777Sender`, `IERC777Recipient`.
This diff is collapsed. Click to expand it.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment