Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ada3b633e | |||
| 45b81c969f | |||
| f2fb8cf23b | |||
| 9f900f6dba | |||
| 91f16a7e47 | |||
| 6bc2ae3731 | |||
| 885b76f66f | |||
| ded2b0a55c | |||
| 0f08b1d099 | |||
| aaa5ef81cf | |||
| cb791a1b21 | |||
| 0b489f4d79 | |||
| 1f06fd7e66 | |||
| e5da0986bb | |||
| 0fc9578fe6 | |||
| b1ea59e814 | |||
| 7d48d79b53 | |||
| 6d5a73815d | |||
| d1f336d8fd | |||
| 9700e6b4bd | |||
| 722879b32d | |||
| 943a663a31 | |||
| 09014f90f9 | |||
| 0c667ca32a | |||
| 7c4a2a0a29 | |||
| c801c8d2bb | |||
| 98e862e162 | |||
| b9d72d2991 | |||
| c6612871fb | |||
| b991fca341 | |||
| ef3bbbcf40 | |||
| 32f0fe5d08 | |||
| 6d987f1418 | |||
| de99bccbfd | |||
| 0cc882ef9d | |||
| 3f4420527b | |||
| 21d06999f6 | |||
| f3803d3a5d | |||
| c6da044dc5 | |||
| 02a6b05bde | |||
| 242400e9ea | |||
| 8c1daaab57 | |||
| 7f62c8e145 | |||
| e2876b947d | |||
| ed3a513f86 | |||
| b72088a90a | |||
| 8b58fc7191 | |||
| d9fa59f30a | |||
| 13e2132b69 | |||
| 298e1b5fdc | |||
| 82769e54c3 | |||
| 022f2bc177 | |||
| ccf79ee483 | |||
| ecf0725dd1 | |||
| d3ef93a9a5 | |||
| 47a7a575e8 | |||
| ff8fe4be7e | |||
| d7a6e7be2e | |||
| a81e948fc9 | |||
| ccfd370b89 | |||
| 91516b2318 | |||
| 52f7b6e03b | |||
| 64ab594ad6 | |||
| 394987f365 | |||
| df4b317fb3 | |||
| 142f6c3f05 | |||
| 414adb94f0 | |||
| 7ee98cf525 | |||
| d418da6b91 | |||
| 2a0f2a8ba8 | |||
| 5513dfd3cf | |||
| c18ffd7c81 | |||
| 424ab2a024 | |||
| e2b97d6712 | |||
| 217a616fde | |||
| 56de324afe | |||
| fa36244bec | |||
| 4fe31f8d4d | |||
| cfa9ad9943 | |||
| fd981ad315 | |||
| 5f9a86a8f2 | |||
| 956d6632d9 | |||
| 0c7b2ec09e | |||
| 4cbcaf35e4 | |||
| 73baf0b635 | |||
| 78dc37739f | |||
| ac0a4327a9 | |||
| c20e620a06 | |||
| 4bc45e35c2 | |||
| b362e886ec | |||
| ca38899ede | |||
| 61973af29f |
@ -1,7 +0,0 @@
|
||||
version: 1
|
||||
|
||||
update_configs:
|
||||
- package_manager: "javascript"
|
||||
directory: "/"
|
||||
update_schedule: "weekly"
|
||||
version_requirement_updates: "increase_versions"
|
||||
@ -8,7 +8,7 @@ charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
trim_trailing_whitespace = false
|
||||
max_line_length = 120
|
||||
|
||||
[*.sol]
|
||||
@ -16,3 +16,6 @@ indent_size = 4
|
||||
|
||||
[*.js]
|
||||
indent_size = 2
|
||||
|
||||
[*.adoc]
|
||||
max_line_length = 0
|
||||
|
||||
3
.mocharc.js
Normal file
3
.mocharc.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
timeout: 4000,
|
||||
};
|
||||
@ -5,6 +5,7 @@
|
||||
"mark-callable-contracts": "off",
|
||||
"no-empty-blocks": "off",
|
||||
"compiler-version": ["error", "^0.6.0"],
|
||||
"private-vars-leading-underscore": "error"
|
||||
"private-vars-leading-underscore": "error",
|
||||
"reason-string": "off"
|
||||
}
|
||||
}
|
||||
|
||||
38
CHANGELOG.md
38
CHANGELOG.md
@ -1,5 +1,43 @@
|
||||
# Changelog
|
||||
|
||||
## 3.2.0 (2020-09-10)
|
||||
|
||||
### New features
|
||||
* Proxies: added the proxy contracts from OpenZeppelin SDK. ([#2335](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2335))
|
||||
|
||||
#### Proxy changes with respect to OpenZeppelin SDK
|
||||
|
||||
Aside from upgrading them from Solidity 0.5 to 0.6, we've changed a few minor things from the proxy contracts as they were found in OpenZeppelin SDK.
|
||||
|
||||
- `UpgradeabilityProxy` was renamed to `UpgradeableProxy`.
|
||||
- `AdminUpgradeabilityProxy` was renamed to `TransparentUpgradeableProxy`.
|
||||
- `Proxy._willFallback` was renamed to `Proxy._beforeFallback`.
|
||||
- `UpgradeabilityProxy._setImplementation` and `AdminUpgradeabilityProxy._setAdmin` were made private.
|
||||
|
||||
### Improvements
|
||||
* `Address.isContract`: switched from `extcodehash` to `extcodesize` for less gas usage. ([#2311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2311))
|
||||
|
||||
### Breaking changes
|
||||
* `ERC20Snapshot`: switched to using `_beforeTokenTransfer` hook instead of overriding ERC20 operations. ([#2312](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2312))
|
||||
|
||||
This small change in the way we implemented `ERC20Snapshot` may affect users who are combining this contract with
|
||||
other ERC20 flavors, since it no longer overrides `_transfer`, `_mint`, and `_burn`. This can result in having to remove Solidity `override(...)` specifiers in derived contracts for these functions, and to instead have to add it for `_beforeTokenTransfer`. See [Using Hooks](https://docs.openzeppelin.com/contracts/3.x/extending-contracts#using-hooks) in the documentation.
|
||||
|
||||
## 3.1.0 (2020-06-23)
|
||||
|
||||
### New features
|
||||
* `SafeCast`: added functions to downcast signed integers (e.g. `toInt32`), improving usability of `SignedSafeMath`. ([#2243](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2243))
|
||||
* `functionCall`: new helpers that replicate Solidity's function call semantics, reducing the need to rely on `call`. ([#2264](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2264))
|
||||
* `ERC1155`: added support for a base implementation, non-standard extensions and a preset contract. ([#2014](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2014), [#2230](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2230))
|
||||
|
||||
### Improvements
|
||||
* `ReentrancyGuard`: reduced overhead of using the `nonReentrant` modifier. ([#2171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2171))
|
||||
* `AccessControl`: added a `RoleAdminChanged` event to `_setAdminRole`. ([#2214](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2214))
|
||||
* Made all `public` functions in the token preset contracts `virtual`. ([#2257](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2257))
|
||||
|
||||
### Deprecations
|
||||
* `SafeERC20`: deprecated `safeApprove`. ([#2268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2268))
|
||||
|
||||
## 3.0.2 (2020-06-08)
|
||||
|
||||
### Improvements
|
||||
|
||||
@ -1,69 +0,0 @@
|
||||
# Code Style
|
||||
|
||||
We value clean code and consistency, and those are prerequisites for us to
|
||||
include new code in the repository. Before proposing a change, please read this
|
||||
document and take some time to familiarize yourself with the style of the
|
||||
existing codebase.
|
||||
|
||||
## Solidity code
|
||||
|
||||
In order to be consistent with all the other Solidity projects, we follow the
|
||||
[official recommendations documented in the Solidity style guide](http://solidity.readthedocs.io/en/latest/style-guide.html).
|
||||
|
||||
Any exception or additions specific to our project are documented below.
|
||||
|
||||
### Naming
|
||||
|
||||
* Try to avoid acronyms and abbreviations.
|
||||
|
||||
* All state variables should be private.
|
||||
|
||||
* Private state variables should have an underscore prefix.
|
||||
|
||||
```
|
||||
contract TestContract {
|
||||
uint256 private _privateVar;
|
||||
uint256 internal _internalVar;
|
||||
}
|
||||
```
|
||||
|
||||
* Parameters must not be prefixed with an underscore.
|
||||
|
||||
```
|
||||
function test(uint256 testParameter1, uint256 testParameter2) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
* Internal and private functions should have an underscore prefix.
|
||||
|
||||
```
|
||||
function _testInternal() internal {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
function _testPrivate() private {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
* Events should be emitted immediately after the state change that they
|
||||
represent, and consequently they should be named in past tense.
|
||||
|
||||
```
|
||||
function _burn(address _who, uint256 _value) internal {
|
||||
super._burn(_who, _value);
|
||||
emit TokensBurned(_who, _value);
|
||||
}
|
||||
```
|
||||
|
||||
Some standards (e.g. ERC20) use present tense, and in those cases the
|
||||
standard specification prevails.
|
||||
|
||||
* Interface names should have a capital I prefix.
|
||||
|
||||
```
|
||||
interface IERC777 {
|
||||
```
|
||||
@ -10,7 +10,7 @@ program that extracts the API Reference from source code.
|
||||
|
||||
The [`docs.openzeppelin.com`](https://github.com/OpenZeppelin/docs.openzeppelin.com)
|
||||
repository hosts the configuration for the entire site, which includes
|
||||
documetation for all of the OpenZeppelin projects.
|
||||
documentation for all of the OpenZeppelin projects.
|
||||
|
||||
To run the docs locally you should run `npm run docs start` on this
|
||||
To run the docs locally you should run `npm run docs:watch` on this
|
||||
repository.
|
||||
|
||||
@ -28,37 +28,78 @@ Consistency on the way classes are used is paramount to an easier understanding
|
||||
#### 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
|
||||
# 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.
|
||||
The design guidelines have quite a high abstraction level. These style guidelines are more concrete and easier to apply, and also more opinionated. We value clean code and consistency, and those are prerequisites for us to include new code in the repository. Before proposing a change, please read these guidelines and take some time to familiarize yourself with the style of the existing codebase.
|
||||
|
||||
### General
|
||||
## Solidity code
|
||||
|
||||
#### G0 - Default to Solidity's official style guide.
|
||||
In order to be consistent with all the other Solidity projects, we follow the
|
||||
[official recommendations documented in the Solidity style guide](http://solidity.readthedocs.io/en/latest/style-guide.html).
|
||||
|
||||
Follow the official Solidity style guide: https://solidity.readthedocs.io/en/latest/style-guide.html
|
||||
Any exception or additions specific to our project are documented below.
|
||||
|
||||
#### G1 - No Magic Constants
|
||||
* Try to avoid acronyms and abbreviations.
|
||||
|
||||
Avoid constants in the code as much as possible. Magic strings are also magic constants.
|
||||
* All state variables should be private.
|
||||
|
||||
#### G2 - Code that Fails Early
|
||||
* Private state variables should have an underscore prefix.
|
||||
|
||||
We ask our code to fail as soon as possible when an unexpected input was provided or unexpected state was found.
|
||||
```
|
||||
contract TestContract {
|
||||
uint256 private _privateVar;
|
||||
uint256 internal _internalVar;
|
||||
}
|
||||
```
|
||||
|
||||
#### G3 - Internal Amounts Must be Signed Integers and Represent the Smallest Units.
|
||||
* Parameters must not be prefixed with an underscore.
|
||||
|
||||
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.
|
||||
```
|
||||
function test(uint256 testParameter1, uint256 testParameter2) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
* Internal and private functions should have an underscore prefix.
|
||||
|
||||
```
|
||||
function _testInternal() internal {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
function _testPrivate() private {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
* Events should be emitted immediately after the state change that they
|
||||
represent, and consequently they should be named in past tense.
|
||||
|
||||
```
|
||||
function _burn(address who, uint256 value) internal {
|
||||
super._burn(who, value);
|
||||
emit TokensBurned(who, value);
|
||||
}
|
||||
```
|
||||
|
||||
Some standards (e.g. ERC20) use present tense, and in those cases the
|
||||
standard specification prevails.
|
||||
|
||||
* Interface names should have a capital I prefix.
|
||||
|
||||
```
|
||||
interface IERC777 {
|
||||
```
|
||||
|
||||
|
||||
### Testing
|
||||
## Tests
|
||||
|
||||
#### T1 - Tests Must be Written Elegantly
|
||||
* 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.
|
||||
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.
|
||||
|
||||
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.
|
||||
* Tests Must not be Random
|
||||
|
||||
#### 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.
|
||||
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.
|
||||
|
||||
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 zOS Global Limited
|
||||
Copyright (c) 2016-2020 zOS Global Limited
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
13
README.md
13
README.md
@ -1,4 +1,4 @@
|
||||
# <img src="logo.png" alt="OpenZeppelin" height="40px">
|
||||
# <img src="logo.svg" alt="OpenZeppelin" height="40px">
|
||||
|
||||
[](https://docs.openzeppelin.com/contracts)
|
||||
[](https://www.npmjs.org/package/@openzeppelin/contracts)
|
||||
@ -28,13 +28,12 @@ OpenZeppelin Contracts features a [stable API](https://docs.openzeppelin.com/con
|
||||
Once installed, you can use the contracts in the library by importing them:
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.5.0;
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721Full.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721Mintable.sol";
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
|
||||
contract MyNFT is ERC721Full, ERC721Mintable {
|
||||
constructor() ERC721Full("MyNFT", "MNFT") public {
|
||||
contract MyCollectible is ERC721 {
|
||||
constructor() ERC721("MyCollectible", "MCO") public {
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -45,7 +44,7 @@ To keep your system secure, you should **always** use the installed code as-is,
|
||||
|
||||
## Learn More
|
||||
|
||||
The guides in the sidebar will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides:
|
||||
The guides in the [docs site](https://docs.openzeppelin.com/contracts) will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides:
|
||||
|
||||
* [Access Control](https://docs.openzeppelin.com/contracts/access-control): decide who can perform each of the actions on your system.
|
||||
* [Tokens](https://docs.openzeppelin.com/contracts/tokens): create tradeable assets or collectives, and distribute them via [Crowdsales](https://docs.openzeppelin.com/contracts/crowdsales).
|
||||
|
||||
@ -12,11 +12,7 @@ pragma solidity ^0.6.0;
|
||||
*
|
||||
* This contract is only required for intermediate, library-like contracts.
|
||||
*/
|
||||
contract Context {
|
||||
// Empty internal constructor, to prevent people from mistakenly deploying
|
||||
// an instance of this contract, which should be used via inheritance.
|
||||
constructor () internal { }
|
||||
|
||||
abstract contract Context {
|
||||
function _msgSender() internal view virtual returns (address payable) {
|
||||
return msg.sender;
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
|
||||
/**
|
||||
* @dev See `IRelayRecipient.preRelayedCall`.
|
||||
*
|
||||
* This function should not be overriden directly, use `_preRelayedCall` instead.
|
||||
* This function should not be overridden directly, use `_preRelayedCall` instead.
|
||||
*
|
||||
* * Requirements:
|
||||
*
|
||||
@ -138,7 +138,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
|
||||
/**
|
||||
* @dev See `IRelayRecipient.postRelayedCall`.
|
||||
*
|
||||
* This function should not be overriden directly, use `_postRelayedCall` instead.
|
||||
* This function should not be overridden directly, use `_postRelayedCall` instead.
|
||||
*
|
||||
* * Requirements:
|
||||
*
|
||||
|
||||
@ -41,7 +41,7 @@ interface IRelayHub {
|
||||
function registerRelay(uint256 transactionFee, string calldata url) external;
|
||||
|
||||
/**
|
||||
* @dev Emitted when a relay is registered or re-registerd. Looking at these events (and filtering out
|
||||
* @dev Emitted when a relay is registered or re-registered. Looking at these events (and filtering out
|
||||
* {RelayRemoved} events) lets a client discover the list of available relays.
|
||||
*/
|
||||
event RelayAdded(address indexed relay, address indexed owner, uint256 transactionFee, uint256 stake, uint256 unstakeDelay, string url);
|
||||
@ -105,7 +105,7 @@ interface IRelayHub {
|
||||
event Deposited(address indexed recipient, address indexed from, uint256 amount);
|
||||
|
||||
/**
|
||||
* @dev Returns an account's deposits. These can be either a contracts's funds, or a relay owner's revenue.
|
||||
* @dev Returns an account's deposits. These can be either a contract's funds, or a relay owner's revenue.
|
||||
*/
|
||||
function balanceOf(address target) external view returns (uint256);
|
||||
|
||||
@ -180,7 +180,7 @@ interface IRelayHub {
|
||||
* - `gasLimit`: gas to forward when calling the encoded function
|
||||
* - `nonce`: client's nonce
|
||||
* - `signature`: client's signature over all previous params, plus the relay and RelayHub addresses
|
||||
* - `approvalData`: dapp-specific data forwared to {acceptRelayedCall}. This value is *not* verified by the
|
||||
* - `approvalData`: dapp-specific data forwarded to {acceptRelayedCall}. This value is *not* verified by the
|
||||
* `RelayHub`, but it still can be used for e.g. a signature.
|
||||
*
|
||||
* Emits a {TransactionRelayed} event.
|
||||
|
||||
@ -53,7 +53,7 @@ interface IRelayRecipient {
|
||||
*
|
||||
* 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
|
||||
* {preRelayedCall} is called with 100k gas: if it runs out during execution 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);
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
= Gas Station Network (GSN)
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/gsn
|
||||
|
||||
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:learn::sending-gasless-transactions.adoc[overview of the system] and basic guide to xref:ROOT:gsn.adoc[creating a GSN-capable contract].
|
||||
|
||||
@ -54,6 +54,16 @@ abstract contract AccessControl is Context {
|
||||
|
||||
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
|
||||
|
||||
/**
|
||||
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
|
||||
*
|
||||
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
|
||||
* {RoleAdminChanged} not being emitted signaling this.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
|
||||
|
||||
/**
|
||||
* @dev Emitted when `account` is granted `role`.
|
||||
*
|
||||
@ -185,8 +195,11 @@ abstract contract AccessControl is Context {
|
||||
|
||||
/**
|
||||
* @dev Sets `adminRole` as ``role``'s admin role.
|
||||
*
|
||||
* Emits a {RoleAdminChanged} event.
|
||||
*/
|
||||
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
|
||||
emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
|
||||
_roles[role].adminRole = adminRole;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
= Access
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access
|
||||
|
||||
Contract modules for authorization and access control mechanisms.
|
||||
|
||||
== Contracts
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
= Cryptography
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/cryptography
|
||||
|
||||
This collection of libraries provides simple and safe ways to use different cryptographic primitives.
|
||||
|
||||
== Libraries
|
||||
|
||||
@ -1,174 +0,0 @@
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../token/ERC20/SafeERC20.sol";
|
||||
import "../access/Ownable.sol";
|
||||
import "../math/SafeMath.sol";
|
||||
|
||||
/**
|
||||
* @title TokenVesting
|
||||
* @dev A token holder contract that can release its token balance gradually like a
|
||||
* typical vesting scheme, with a cliff and vesting period. Optionally revocable by the
|
||||
* owner.
|
||||
*/
|
||||
contract TokenVesting is Ownable {
|
||||
// The vesting schedule is time-based (i.e. using block timestamps as opposed to e.g. block numbers), and is
|
||||
// therefore sensitive to timestamp manipulation (which is something miners can do, to a certain degree). Therefore,
|
||||
// it is recommended to avoid using short time durations (less than a minute). Typical vesting schemes, with a
|
||||
// cliff period of a year and a duration of four years, are safe to use.
|
||||
// solhint-disable not-rely-on-time
|
||||
|
||||
using SafeMath for uint256;
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
event TokensReleased(address token, uint256 amount);
|
||||
event TokenVestingRevoked(address token);
|
||||
|
||||
// beneficiary of tokens after they are released
|
||||
address private _beneficiary;
|
||||
|
||||
// Durations and timestamps are expressed in UNIX time, the same units as block.timestamp.
|
||||
uint256 private _cliff;
|
||||
uint256 private _start;
|
||||
uint256 private _duration;
|
||||
|
||||
bool private _revocable;
|
||||
|
||||
mapping (address => uint256) private _released;
|
||||
mapping (address => bool) private _revoked;
|
||||
|
||||
/**
|
||||
* @dev Creates a vesting contract that vests its balance of any ERC20 token to the
|
||||
* beneficiary, gradually in a linear fashion until start + duration. By then all
|
||||
* of the balance will have vested.
|
||||
* @param beneficiary address of the beneficiary to whom vested tokens are transferred
|
||||
* @param cliffDuration duration in seconds of the cliff in which tokens will begin to vest
|
||||
* @param start the time (as Unix time) at which point vesting starts
|
||||
* @param duration duration in seconds of the period in which the tokens will vest
|
||||
* @param revocable whether the vesting is revocable or not
|
||||
*/
|
||||
constructor (address beneficiary, uint256 start, uint256 cliffDuration, uint256 duration, bool revocable) public {
|
||||
require(beneficiary != address(0), "TokenVesting: beneficiary is the zero address");
|
||||
// solhint-disable-next-line max-line-length
|
||||
require(cliffDuration <= duration, "TokenVesting: cliff is longer than duration");
|
||||
require(duration > 0, "TokenVesting: duration is 0");
|
||||
// solhint-disable-next-line max-line-length
|
||||
require(start.add(duration) > block.timestamp, "TokenVesting: final time is before current time");
|
||||
|
||||
_beneficiary = beneficiary;
|
||||
_revocable = revocable;
|
||||
_duration = duration;
|
||||
_cliff = start.add(cliffDuration);
|
||||
_start = start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the beneficiary of the tokens.
|
||||
*/
|
||||
function beneficiary() public view returns (address) {
|
||||
return _beneficiary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the cliff time of the token vesting.
|
||||
*/
|
||||
function cliff() public view returns (uint256) {
|
||||
return _cliff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the start time of the token vesting.
|
||||
*/
|
||||
function start() public view returns (uint256) {
|
||||
return _start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the duration of the token vesting.
|
||||
*/
|
||||
function duration() public view returns (uint256) {
|
||||
return _duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the vesting is revocable.
|
||||
*/
|
||||
function revocable() public view returns (bool) {
|
||||
return _revocable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the amount of the token released.
|
||||
*/
|
||||
function released(address token) public view returns (uint256) {
|
||||
return _released[token];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the token is revoked.
|
||||
*/
|
||||
function revoked(address token) public view returns (bool) {
|
||||
return _revoked[token];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Transfers vested tokens to beneficiary.
|
||||
* @param token ERC20 token which is being vested
|
||||
*/
|
||||
function release(IERC20 token) public {
|
||||
uint256 unreleased = _releasableAmount(token);
|
||||
|
||||
require(unreleased > 0, "TokenVesting: no tokens are due");
|
||||
|
||||
_released[address(token)] = _released[address(token)].add(unreleased);
|
||||
|
||||
token.safeTransfer(_beneficiary, unreleased);
|
||||
|
||||
emit TokensReleased(address(token), unreleased);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Allows the owner to revoke the vesting. Tokens already vested
|
||||
* remain in the contract, the rest are returned to the owner.
|
||||
* @param token ERC20 token which is being vested
|
||||
*/
|
||||
function revoke(IERC20 token) public onlyOwner {
|
||||
require(_revocable, "TokenVesting: cannot revoke");
|
||||
require(!_revoked[address(token)], "TokenVesting: token already revoked");
|
||||
|
||||
uint256 balance = token.balanceOf(address(this));
|
||||
|
||||
uint256 unreleased = _releasableAmount(token);
|
||||
uint256 refund = balance.sub(unreleased);
|
||||
|
||||
_revoked[address(token)] = true;
|
||||
|
||||
token.safeTransfer(owner(), refund);
|
||||
|
||||
emit TokenVestingRevoked(address(token));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the amount that has already vested but hasn't been released yet.
|
||||
* @param token ERC20 token which is being vested
|
||||
*/
|
||||
function _releasableAmount(IERC20 token) private view returns (uint256) {
|
||||
return _vestedAmount(token).sub(_released[address(token)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Calculates the amount that has already vested.
|
||||
* @param token ERC20 token which is being vested
|
||||
*/
|
||||
function _vestedAmount(IERC20 token) private view returns (uint256) {
|
||||
uint256 currentBalance = token.balanceOf(address(this));
|
||||
uint256 totalBalance = currentBalance.add(_released[address(token)]);
|
||||
|
||||
if (block.timestamp < _cliff) {
|
||||
return 0;
|
||||
} else if (block.timestamp >= _start.add(_duration) || _revoked[address(token)]) {
|
||||
return totalBalance;
|
||||
} else {
|
||||
return totalBalance.mul(block.timestamp.sub(_start)).div(_duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
= Introspection
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/introspection
|
||||
|
||||
This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[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.
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
= Math
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/math
|
||||
|
||||
These are math-related utilities.
|
||||
|
||||
== Libraries
|
||||
|
||||
@ -23,6 +23,7 @@ library SafeMath {
|
||||
* Counterpart to Solidity's `+` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Addition cannot overflow.
|
||||
*/
|
||||
function add(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
@ -39,6 +40,7 @@ library SafeMath {
|
||||
* Counterpart to Solidity's `-` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Subtraction cannot overflow.
|
||||
*/
|
||||
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
@ -52,6 +54,7 @@ library SafeMath {
|
||||
* Counterpart to Solidity's `-` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Subtraction cannot overflow.
|
||||
*/
|
||||
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
|
||||
@ -68,6 +71,7 @@ library SafeMath {
|
||||
* Counterpart to Solidity's `*` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Multiplication cannot overflow.
|
||||
*/
|
||||
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
@ -93,6 +97,7 @@ library SafeMath {
|
||||
* uses an invalid opcode to revert (consuming all remaining gas).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function div(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
@ -108,10 +113,10 @@ library SafeMath {
|
||||
* uses an invalid opcode to revert (consuming all remaining gas).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
|
||||
// Solidity only automatically asserts when dividing by 0
|
||||
require(b > 0, errorMessage);
|
||||
uint256 c = a / b;
|
||||
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
|
||||
@ -128,6 +133,7 @@ library SafeMath {
|
||||
* invalid opcode to revert (consuming all remaining gas).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
|
||||
@ -143,6 +149,7 @@ library SafeMath {
|
||||
* invalid opcode to revert (consuming all remaining gas).
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The divisor cannot be zero.
|
||||
*/
|
||||
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
|
||||
|
||||
@ -10,7 +10,14 @@ library SignedSafeMath {
|
||||
int256 constant private _INT256_MIN = -2**255;
|
||||
|
||||
/**
|
||||
* @dev Multiplies two signed integers, reverts on overflow.
|
||||
* @dev Returns the multiplication of two signed integers, reverting on
|
||||
* overflow.
|
||||
*
|
||||
* Counterpart to Solidity's `*` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Multiplication cannot overflow.
|
||||
*/
|
||||
function mul(int256 a, int256 b) internal pure returns (int256) {
|
||||
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
|
||||
@ -29,7 +36,16 @@ library SignedSafeMath {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Integer division of two signed integers truncating the quotient, reverts on division by zero.
|
||||
* @dev Returns the integer division of two signed integers. Reverts 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.
|
||||
*/
|
||||
function div(int256 a, int256 b) internal pure returns (int256) {
|
||||
require(b != 0, "SignedSafeMath: division by zero");
|
||||
@ -41,7 +57,14 @@ library SignedSafeMath {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Subtracts two signed integers, reverts on overflow.
|
||||
* @dev Returns the subtraction of two signed integers, reverting on
|
||||
* overflow.
|
||||
*
|
||||
* Counterpart to Solidity's `-` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Subtraction cannot overflow.
|
||||
*/
|
||||
function sub(int256 a, int256 b) internal pure returns (int256) {
|
||||
int256 c = a - b;
|
||||
@ -51,7 +74,14 @@ library SignedSafeMath {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Adds two signed integers, reverts on overflow.
|
||||
* @dev Returns the addition of two signed integers, reverting on
|
||||
* overflow.
|
||||
*
|
||||
* Counterpart to Solidity's `+` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - Addition cannot overflow.
|
||||
*/
|
||||
function add(int256 a, int256 b) internal pure returns (int256) {
|
||||
int256 c = a + b;
|
||||
|
||||
@ -5,6 +5,8 @@ pragma solidity ^0.6.0;
|
||||
import "../utils/Address.sol";
|
||||
|
||||
contract AddressImpl {
|
||||
event CallReturnValue(string data);
|
||||
|
||||
function isContract(address account) external view returns (bool) {
|
||||
return Address.isContract(account);
|
||||
}
|
||||
@ -13,6 +15,18 @@ contract AddressImpl {
|
||||
Address.sendValue(receiver, amount);
|
||||
}
|
||||
|
||||
function functionCall(address target, bytes calldata data) external {
|
||||
bytes memory returnData = Address.functionCall(target, data);
|
||||
|
||||
emit CallReturnValue(abi.decode(returnData, (string)));
|
||||
}
|
||||
|
||||
function functionCallWithValue(address target, bytes calldata data, uint256 value) external payable {
|
||||
bytes memory returnData = Address.functionCallWithValue(target, data, value);
|
||||
|
||||
emit CallReturnValue(abi.decode(returnData, (string)));
|
||||
}
|
||||
|
||||
// sendValue's tests require the contract to hold Ether
|
||||
receive () external payable { }
|
||||
}
|
||||
|
||||
40
contracts/mocks/CallReceiverMock.sol
Normal file
40
contracts/mocks/CallReceiverMock.sol
Normal file
@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
contract CallReceiverMock {
|
||||
|
||||
event MockFunctionCalled();
|
||||
|
||||
uint256[] private _array;
|
||||
|
||||
function mockFunction() public payable returns (string memory) {
|
||||
emit MockFunctionCalled();
|
||||
|
||||
return "0x1234";
|
||||
}
|
||||
|
||||
function mockFunctionNonPayable() public returns (string memory) {
|
||||
emit MockFunctionCalled();
|
||||
|
||||
return "0x1234";
|
||||
}
|
||||
|
||||
function mockFunctionRevertsNoReason() public payable {
|
||||
revert();
|
||||
}
|
||||
|
||||
function mockFunctionRevertsReason() public payable {
|
||||
revert("CallReceiverMock: reverting");
|
||||
}
|
||||
|
||||
function mockFunctionThrows() public payable {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
function mockFunctionOutOfGas() public payable {
|
||||
for (uint256 i = 0; ; ++i) {
|
||||
_array.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
contracts/mocks/ClashingImplementation.sol
Normal file
20
contracts/mocks/ClashingImplementation.sol
Normal file
@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
|
||||
/**
|
||||
* @dev Implementation contract with an admin() function made to clash with
|
||||
* @dev TransparentUpgradeableProxy's to test correct functioning of the
|
||||
* @dev Transparent Proxy feature.
|
||||
*/
|
||||
contract ClashingImplementation {
|
||||
|
||||
function admin() external pure returns (address) {
|
||||
return 0x0000000000000000000000000000000011111142;
|
||||
}
|
||||
|
||||
function delegatedFunction() external pure returns (bool) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
57
contracts/mocks/DummyImplementation.sol
Normal file
57
contracts/mocks/DummyImplementation.sol
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
abstract contract Impl {
|
||||
function version() public pure virtual returns (string memory);
|
||||
}
|
||||
|
||||
contract DummyImplementation {
|
||||
uint256 public value;
|
||||
string public text;
|
||||
uint256[] public values;
|
||||
|
||||
function initializeNonPayable() public {
|
||||
value = 10;
|
||||
}
|
||||
|
||||
function initializePayable() payable public {
|
||||
value = 100;
|
||||
}
|
||||
|
||||
function initializeNonPayable(uint256 _value) public {
|
||||
value = _value;
|
||||
}
|
||||
|
||||
function initializePayable(uint256 _value) payable public {
|
||||
value = _value;
|
||||
}
|
||||
|
||||
function initialize(uint256 _value, string memory _text, uint256[] memory _values) public {
|
||||
value = _value;
|
||||
text = _text;
|
||||
values = _values;
|
||||
}
|
||||
|
||||
function get() public pure returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function version() public pure virtual returns (string memory) {
|
||||
return "V1";
|
||||
}
|
||||
|
||||
function reverts() public pure {
|
||||
require(false);
|
||||
}
|
||||
}
|
||||
|
||||
contract DummyImplementationV2 is DummyImplementation {
|
||||
function migrate(uint256 newVal) payable public {
|
||||
value = newVal;
|
||||
}
|
||||
|
||||
function version() public pure override returns (string memory) {
|
||||
return "V2";
|
||||
}
|
||||
}
|
||||
13
contracts/mocks/ERC1155BurnableMock.sol
Normal file
13
contracts/mocks/ERC1155BurnableMock.sol
Normal file
@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../token/ERC1155/ERC1155Burnable.sol";
|
||||
|
||||
contract ERC1155BurnableMock is ERC1155Burnable {
|
||||
constructor(string memory uri) public ERC1155(uri) { }
|
||||
|
||||
function mint(address to, uint256 id, uint256 value, bytes memory data) public {
|
||||
_mint(to, id, value, data);
|
||||
}
|
||||
}
|
||||
35
contracts/mocks/ERC1155Mock.sol
Normal file
35
contracts/mocks/ERC1155Mock.sol
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../token/ERC1155/ERC1155.sol";
|
||||
|
||||
/**
|
||||
* @title ERC1155Mock
|
||||
* This mock just publicizes internal functions for testing purposes
|
||||
*/
|
||||
contract ERC1155Mock is ERC1155 {
|
||||
constructor (string memory uri) public ERC1155(uri) {
|
||||
// solhint-disable-previous-line no-empty-blocks
|
||||
}
|
||||
|
||||
function setURI(string memory newuri) public {
|
||||
_setURI(newuri);
|
||||
}
|
||||
|
||||
function mint(address to, uint256 id, uint256 value, bytes memory data) public {
|
||||
_mint(to, id, value, data);
|
||||
}
|
||||
|
||||
function mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) public {
|
||||
_mintBatch(to, ids, values, data);
|
||||
}
|
||||
|
||||
function burn(address owner, uint256 id, uint256 value) public {
|
||||
_burn(owner, id, value);
|
||||
}
|
||||
|
||||
function burnBatch(address owner, uint256[] memory ids, uint256[] memory values) public {
|
||||
_burnBatch(owner, ids, values);
|
||||
}
|
||||
}
|
||||
31
contracts/mocks/ERC1155PausableMock.sol
Normal file
31
contracts/mocks/ERC1155PausableMock.sol
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./ERC1155Mock.sol";
|
||||
import "../token/ERC1155/ERC1155Pausable.sol";
|
||||
|
||||
contract ERC1155PausableMock is ERC1155Mock, ERC1155Pausable {
|
||||
constructor(string memory uri) public ERC1155Mock(uri) { }
|
||||
|
||||
function pause() external {
|
||||
_pause();
|
||||
}
|
||||
|
||||
function unpause() external {
|
||||
_unpause();
|
||||
}
|
||||
|
||||
function _beforeTokenTransfer(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
internal virtual override(ERC1155, ERC1155Pausable)
|
||||
{
|
||||
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
|
||||
}
|
||||
}
|
||||
62
contracts/mocks/ERC1155ReceiverMock.sol
Normal file
62
contracts/mocks/ERC1155ReceiverMock.sol
Normal file
@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../token/ERC1155/IERC1155Receiver.sol";
|
||||
import "./ERC165Mock.sol";
|
||||
|
||||
contract ERC1155ReceiverMock is IERC1155Receiver, ERC165Mock {
|
||||
bytes4 private _recRetval;
|
||||
bool private _recReverts;
|
||||
bytes4 private _batRetval;
|
||||
bool private _batReverts;
|
||||
|
||||
event Received(address operator, address from, uint256 id, uint256 value, bytes data, uint256 gas);
|
||||
event BatchReceived(address operator, address from, uint256[] ids, uint256[] values, bytes data, uint256 gas);
|
||||
|
||||
constructor (
|
||||
bytes4 recRetval,
|
||||
bool recReverts,
|
||||
bytes4 batRetval,
|
||||
bool batReverts
|
||||
)
|
||||
public
|
||||
{
|
||||
_recRetval = recRetval;
|
||||
_recReverts = recReverts;
|
||||
_batRetval = batRetval;
|
||||
_batReverts = batReverts;
|
||||
}
|
||||
|
||||
function onERC1155Received(
|
||||
address operator,
|
||||
address from,
|
||||
uint256 id,
|
||||
uint256 value,
|
||||
bytes calldata data
|
||||
)
|
||||
external
|
||||
override
|
||||
returns(bytes4)
|
||||
{
|
||||
require(!_recReverts, "ERC1155ReceiverMock: reverting on receive");
|
||||
emit Received(operator, from, id, value, data, gasleft());
|
||||
return _recRetval;
|
||||
}
|
||||
|
||||
function onERC1155BatchReceived(
|
||||
address operator,
|
||||
address from,
|
||||
uint256[] calldata ids,
|
||||
uint256[] calldata values,
|
||||
bytes calldata data
|
||||
)
|
||||
external
|
||||
override
|
||||
returns(bytes4)
|
||||
{
|
||||
require(!_batReverts, "ERC1155ReceiverMock: reverting on batch receive");
|
||||
emit BatchReceived(operator, from, ids, values, data, gasleft());
|
||||
return _batRetval;
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,8 @@ pragma solidity ^0.6.0;
|
||||
|
||||
import "../utils/EnumerableSet.sol";
|
||||
|
||||
contract EnumerableSetMock {
|
||||
// AddressSet
|
||||
contract EnumerableAddressSetMock {
|
||||
using EnumerableSet for EnumerableSet.AddressSet;
|
||||
|
||||
event OperationResult(bool result);
|
||||
@ -33,3 +34,34 @@ contract EnumerableSetMock {
|
||||
return _set.at(index);
|
||||
}
|
||||
}
|
||||
|
||||
// UintSet
|
||||
contract EnumerableUintSetMock {
|
||||
using EnumerableSet for EnumerableSet.UintSet;
|
||||
|
||||
event OperationResult(bool result);
|
||||
|
||||
EnumerableSet.UintSet private _set;
|
||||
|
||||
function contains(uint256 value) public view returns (bool) {
|
||||
return _set.contains(value);
|
||||
}
|
||||
|
||||
function add(uint256 value) public {
|
||||
bool result = _set.add(value);
|
||||
emit OperationResult(result);
|
||||
}
|
||||
|
||||
function remove(uint256 value) public {
|
||||
bool result = _set.remove(value);
|
||||
emit OperationResult(result);
|
||||
}
|
||||
|
||||
function length() public view returns (uint256) {
|
||||
return _set.length();
|
||||
}
|
||||
|
||||
function at(uint256 index) public view returns (uint256) {
|
||||
return _set.at(index);
|
||||
}
|
||||
}
|
||||
36
contracts/mocks/InitializableMock.sol
Normal file
36
contracts/mocks/InitializableMock.sol
Normal file
@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../proxy/Initializable.sol";
|
||||
|
||||
/**
|
||||
* @title InitializableMock
|
||||
* @dev This contract is a mock to test initializable functionality
|
||||
*/
|
||||
contract InitializableMock is Initializable {
|
||||
|
||||
bool public initializerRan;
|
||||
uint256 public x;
|
||||
|
||||
function initialize() public initializer {
|
||||
initializerRan = true;
|
||||
}
|
||||
|
||||
function initializeNested() public initializer {
|
||||
initialize();
|
||||
}
|
||||
|
||||
function initializeWithX(uint256 _x) public payable initializer {
|
||||
x = _x;
|
||||
}
|
||||
|
||||
function nonInitializable(uint256 _x) public payable {
|
||||
x = _x;
|
||||
}
|
||||
|
||||
function fail() public pure {
|
||||
require(false, "InitializableMock forced failure");
|
||||
}
|
||||
|
||||
}
|
||||
76
contracts/mocks/MultipleInheritanceInitializableMocks.sol
Normal file
76
contracts/mocks/MultipleInheritanceInitializableMocks.sol
Normal file
@ -0,0 +1,76 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../proxy/Initializable.sol";
|
||||
|
||||
// Sample contracts showing upgradeability with multiple inheritance.
|
||||
// Child contract inherits from Father and Mother contracts, and Father extends from Gramps.
|
||||
//
|
||||
// Human
|
||||
// / \
|
||||
// | Gramps
|
||||
// | |
|
||||
// Mother Father
|
||||
// | |
|
||||
// -- Child --
|
||||
|
||||
/**
|
||||
* Sample base intializable contract that is a human
|
||||
*/
|
||||
contract SampleHuman is Initializable {
|
||||
bool public isHuman;
|
||||
|
||||
function initialize() public initializer {
|
||||
isHuman = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample base intializable contract that defines a field mother
|
||||
*/
|
||||
contract SampleMother is Initializable, SampleHuman {
|
||||
uint256 public mother;
|
||||
|
||||
function initialize(uint256 value) public initializer virtual {
|
||||
SampleHuman.initialize();
|
||||
mother = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample base intializable contract that defines a field gramps
|
||||
*/
|
||||
contract SampleGramps is Initializable, SampleHuman {
|
||||
string public gramps;
|
||||
|
||||
function initialize(string memory value) public initializer virtual {
|
||||
SampleHuman.initialize();
|
||||
gramps = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sample base intializable contract that defines a field father and extends from gramps
|
||||
*/
|
||||
contract SampleFather is Initializable, SampleGramps {
|
||||
uint256 public father;
|
||||
|
||||
function initialize(string memory _gramps, uint256 _father) public initializer {
|
||||
SampleGramps.initialize(_gramps);
|
||||
father = _father;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Child extends from mother, father (gramps)
|
||||
*/
|
||||
contract SampleChild is Initializable, SampleMother, SampleFather {
|
||||
uint256 public child;
|
||||
|
||||
function initialize(uint256 _mother, string memory _gramps, uint256 _father, uint256 _child) public initializer {
|
||||
SampleMother.initialize(_mother);
|
||||
SampleFather.initialize(_gramps, _father);
|
||||
child = _child;
|
||||
}
|
||||
}
|
||||
66
contracts/mocks/RegressionImplementation.sol
Normal file
66
contracts/mocks/RegressionImplementation.sol
Normal file
@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../proxy/Initializable.sol";
|
||||
|
||||
contract Implementation1 is Initializable {
|
||||
uint internal _value;
|
||||
|
||||
function initialize() public initializer {
|
||||
}
|
||||
|
||||
function setValue(uint _number) public {
|
||||
_value = _number;
|
||||
}
|
||||
}
|
||||
|
||||
contract Implementation2 is Initializable {
|
||||
uint internal _value;
|
||||
|
||||
function initialize() public initializer {
|
||||
}
|
||||
|
||||
function setValue(uint _number) public {
|
||||
_value = _number;
|
||||
}
|
||||
|
||||
function getValue() public view returns (uint) {
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
|
||||
contract Implementation3 is Initializable {
|
||||
uint internal _value;
|
||||
|
||||
function initialize() public initializer {
|
||||
}
|
||||
|
||||
function setValue(uint _number) public {
|
||||
_value = _number;
|
||||
}
|
||||
|
||||
function getValue(uint _number) public view returns (uint) {
|
||||
return _value + _number;
|
||||
}
|
||||
}
|
||||
|
||||
contract Implementation4 is Initializable {
|
||||
uint internal _value;
|
||||
|
||||
function initialize() public initializer {
|
||||
}
|
||||
|
||||
function setValue(uint _number) public {
|
||||
_value = _number;
|
||||
}
|
||||
|
||||
function getValue() public view returns (uint) {
|
||||
return _value;
|
||||
}
|
||||
|
||||
// solhint-disable-next-line payable-fallback
|
||||
fallback() external {
|
||||
_value = 1;
|
||||
}
|
||||
}
|
||||
@ -35,4 +35,24 @@ contract SafeCastMock {
|
||||
function toUint8(uint a) public pure returns (uint8) {
|
||||
return a.toUint8();
|
||||
}
|
||||
|
||||
function toInt128(int a) public pure returns (int128) {
|
||||
return a.toInt128();
|
||||
}
|
||||
|
||||
function toInt64(int a) public pure returns (int64) {
|
||||
return a.toInt64();
|
||||
}
|
||||
|
||||
function toInt32(int a) public pure returns (int32) {
|
||||
return a.toInt32();
|
||||
}
|
||||
|
||||
function toInt16(int a) public pure returns (int16) {
|
||||
return a.toInt16();
|
||||
}
|
||||
|
||||
function toInt8(int a) public pure returns (int8) {
|
||||
return a.toInt8();
|
||||
}
|
||||
}
|
||||
|
||||
49
contracts/mocks/SingleInheritanceInitializableMocks.sol
Normal file
49
contracts/mocks/SingleInheritanceInitializableMocks.sol
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../proxy/Initializable.sol";
|
||||
|
||||
/**
|
||||
* @title MigratableMockV1
|
||||
* @dev This contract is a mock to test initializable functionality through migrations
|
||||
*/
|
||||
contract MigratableMockV1 is Initializable {
|
||||
uint256 public x;
|
||||
|
||||
function initialize(uint256 value) public payable initializer {
|
||||
x = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @title MigratableMockV2
|
||||
* @dev This contract is a mock to test migratable functionality with params
|
||||
*/
|
||||
contract MigratableMockV2 is MigratableMockV1 {
|
||||
bool internal _migratedV2;
|
||||
uint256 public y;
|
||||
|
||||
function migrate(uint256 value, uint256 anotherValue) public payable {
|
||||
require(!_migratedV2);
|
||||
x = value;
|
||||
y = anotherValue;
|
||||
_migratedV2 = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @title MigratableMockV3
|
||||
* @dev This contract is a mock to test migratable functionality without params
|
||||
*/
|
||||
contract MigratableMockV3 is MigratableMockV2 {
|
||||
bool internal _migratedV3;
|
||||
|
||||
function migrate() public payable {
|
||||
require(!_migratedV3);
|
||||
uint256 oldX = x;
|
||||
x = y;
|
||||
y = oldX;
|
||||
_migratedV3 = true;
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openzeppelin/contracts",
|
||||
"version": "3.0.2",
|
||||
"version": "3.2.0",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"files": [
|
||||
"**/*.sol",
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
= Payment
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/payment
|
||||
|
||||
Utilities related to sending and receiving payments. Examples are {PullPayment}, which implements the best security practices when sending funds to third parties, and {PaymentSplitter} to receive incoming payments among a number of beneficiaries.
|
||||
|
||||
TIP: When transferring funds to and from untrusted third parties, there is always a security risk of reentrancy. If you would like to learn more about this and ways to protect against it, check out our blog post https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
|
||||
|
||||
104
contracts/presets/ERC1155PresetMinterPauser.sol
Normal file
104
contracts/presets/ERC1155PresetMinterPauser.sol
Normal file
@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../access/AccessControl.sol";
|
||||
import "../GSN/Context.sol";
|
||||
import "../token/ERC1155/ERC1155.sol";
|
||||
import "../token/ERC1155/ERC1155Burnable.sol";
|
||||
import "../token/ERC1155/ERC1155Pausable.sol";
|
||||
|
||||
/**
|
||||
* @dev {ERC1155} token, including:
|
||||
*
|
||||
* - ability for holders to burn (destroy) their tokens
|
||||
* - a minter role that allows for token minting (creation)
|
||||
* - a pauser role that allows to stop all token transfers
|
||||
*
|
||||
* This contract uses {AccessControl} to lock permissioned functions using the
|
||||
* different roles - head to its documentation for details.
|
||||
*
|
||||
* The account that deploys the contract will be granted the minter and pauser
|
||||
* roles, as well as the default admin role, which will let it grant both minter
|
||||
* and pauser roles to other accounts.
|
||||
*/
|
||||
contract ERC1155PresetMinterPauser is Context, AccessControl, ERC1155Burnable, ERC1155Pausable {
|
||||
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
||||
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
|
||||
|
||||
/**
|
||||
* @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE`, and `PAUSER_ROLE` to the account that
|
||||
* deploys the contract.
|
||||
*/
|
||||
constructor(string memory uri) public ERC1155(uri) {
|
||||
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
|
||||
|
||||
_setupRole(MINTER_ROLE, _msgSender());
|
||||
_setupRole(PAUSER_ROLE, _msgSender());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates `amount` new tokens for `to`, of token type `id`.
|
||||
*
|
||||
* See {ERC1155-_mint}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the caller must have the `MINTER_ROLE`.
|
||||
*/
|
||||
function mint(address to, uint256 id, uint256 amount, bytes memory data) public virtual {
|
||||
require(hasRole(MINTER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have minter role to mint");
|
||||
|
||||
_mint(to, id, amount, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] variant of {mint}.
|
||||
*/
|
||||
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public virtual {
|
||||
require(hasRole(MINTER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have minter role to mint");
|
||||
|
||||
_mintBatch(to, ids, amounts, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Pauses all token transfers.
|
||||
*
|
||||
* See {ERC1155Pausable} and {Pausable-_pause}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the caller must have the `PAUSER_ROLE`.
|
||||
*/
|
||||
function pause() public virtual {
|
||||
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have pauser role to pause");
|
||||
_pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Unpauses all token transfers.
|
||||
*
|
||||
* See {ERC1155Pausable} and {Pausable-_unpause}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the caller must have the `PAUSER_ROLE`.
|
||||
*/
|
||||
function unpause() public virtual {
|
||||
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have pauser role to unpause");
|
||||
_unpause();
|
||||
}
|
||||
|
||||
function _beforeTokenTransfer(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
internal virtual override(ERC1155, ERC1155Pausable)
|
||||
{
|
||||
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ import "../token/ERC20/ERC20Pausable.sol";
|
||||
*
|
||||
* The account that deploys the contract will be granted the minter and pauser
|
||||
* roles, as well as the default admin role, which will let it grant both minter
|
||||
* and pauser roles to aother accounts
|
||||
* and pauser roles to other accounts.
|
||||
*/
|
||||
contract ERC20PresetMinterPauser is Context, AccessControl, ERC20Burnable, ERC20Pausable {
|
||||
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
||||
@ -48,7 +48,7 @@ contract ERC20PresetMinterPauser is Context, AccessControl, ERC20Burnable, ERC20
|
||||
*
|
||||
* - the caller must have the `MINTER_ROLE`.
|
||||
*/
|
||||
function mint(address to, uint256 amount) public {
|
||||
function mint(address to, uint256 amount) public virtual {
|
||||
require(hasRole(MINTER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have minter role to mint");
|
||||
_mint(to, amount);
|
||||
}
|
||||
@ -62,7 +62,7 @@ contract ERC20PresetMinterPauser is Context, AccessControl, ERC20Burnable, ERC20
|
||||
*
|
||||
* - the caller must have the `PAUSER_ROLE`.
|
||||
*/
|
||||
function pause() public {
|
||||
function pause() public virtual {
|
||||
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to pause");
|
||||
_pause();
|
||||
}
|
||||
@ -76,12 +76,12 @@ contract ERC20PresetMinterPauser is Context, AccessControl, ERC20Burnable, ERC20
|
||||
*
|
||||
* - the caller must have the `PAUSER_ROLE`.
|
||||
*/
|
||||
function unpause() public {
|
||||
function unpause() public virtual {
|
||||
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to unpause");
|
||||
_unpause();
|
||||
}
|
||||
|
||||
function _beforeTokenTransfer(address from, address to, uint256 amount) internal override(ERC20, ERC20Pausable) {
|
||||
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override(ERC20, ERC20Pausable) {
|
||||
super._beforeTokenTransfer(from, to, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import "../token/ERC721/ERC721Pausable.sol";
|
||||
*
|
||||
* The account that deploys the contract will be granted the minter and pauser
|
||||
* roles, as well as the default admin role, which will let it grant both minter
|
||||
* and pauser roles to aother accounts
|
||||
* and pauser roles to other accounts.
|
||||
*/
|
||||
contract ERC721PresetMinterPauserAutoId is Context, AccessControl, ERC721Burnable, ERC721Pausable {
|
||||
using Counters for Counters.Counter;
|
||||
@ -33,8 +33,8 @@ contract ERC721PresetMinterPauserAutoId is Context, AccessControl, ERC721Burnabl
|
||||
Counters.Counter private _tokenIdTracker;
|
||||
|
||||
/**
|
||||
* @dev Grants `DEFAULT_ADMIN_ROLE` and `MINTER_ROLE` to the account that
|
||||
* deploys the contract.
|
||||
* @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the
|
||||
* account that deploys the contract.
|
||||
*
|
||||
* Token URIs will be autogenerated based on `baseURI` and their token IDs.
|
||||
* See {ERC721-tokenURI}.
|
||||
@ -59,10 +59,10 @@ contract ERC721PresetMinterPauserAutoId is Context, AccessControl, ERC721Burnabl
|
||||
*
|
||||
* - the caller must have the `MINTER_ROLE`.
|
||||
*/
|
||||
function mint(address to) public {
|
||||
function mint(address to) public virtual {
|
||||
require(hasRole(MINTER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have minter role to mint");
|
||||
|
||||
// We can just use balanceOf to create the new tokenId because tokens
|
||||
// We cannot just use balanceOf to create the new tokenId because tokens
|
||||
// can be burned (destroyed), so we need a separate counter.
|
||||
_mint(to, _tokenIdTracker.current());
|
||||
_tokenIdTracker.increment();
|
||||
@ -77,7 +77,7 @@ contract ERC721PresetMinterPauserAutoId is Context, AccessControl, ERC721Burnabl
|
||||
*
|
||||
* - the caller must have the `PAUSER_ROLE`.
|
||||
*/
|
||||
function pause() public {
|
||||
function pause() public virtual {
|
||||
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to pause");
|
||||
_pause();
|
||||
}
|
||||
@ -91,12 +91,12 @@ contract ERC721PresetMinterPauserAutoId is Context, AccessControl, ERC721Burnabl
|
||||
*
|
||||
* - the caller must have the `PAUSER_ROLE`.
|
||||
*/
|
||||
function unpause() public {
|
||||
function unpause() public virtual {
|
||||
require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to unpause");
|
||||
_unpause();
|
||||
}
|
||||
|
||||
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Pausable) {
|
||||
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override(ERC721, ERC721Pausable) {
|
||||
super._beforeTokenTransfer(from, to, tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
= Presets
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/presets
|
||||
|
||||
These contracts integrate different Ethereum standards (ERCs) with custom extensions and modules, showcasing common configurations that are ready to deploy **without having to write any Solidity code**.
|
||||
|
||||
They can be used as-is for quick prototyping and testing, but are **also suitable for production environments**.
|
||||
@ -11,3 +14,5 @@ TIP: Intermediate and advanced users can use these as starting points when writi
|
||||
{{ERC20PresetMinterPauser}}
|
||||
|
||||
{{ERC721PresetMinterPauserAutoId}}
|
||||
|
||||
{{ERC1155PresetMinterPauser}}
|
||||
|
||||
62
contracts/proxy/Initializable.sol
Normal file
62
contracts/proxy/Initializable.sol
Normal file
@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity >=0.4.24 <0.7.0;
|
||||
|
||||
|
||||
/**
|
||||
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
|
||||
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
|
||||
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
|
||||
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
|
||||
*
|
||||
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
|
||||
* possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
|
||||
*
|
||||
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
|
||||
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
|
||||
*/
|
||||
abstract contract Initializable {
|
||||
|
||||
/**
|
||||
* @dev Indicates that the contract has been initialized.
|
||||
*/
|
||||
bool private _initialized;
|
||||
|
||||
/**
|
||||
* @dev Indicates that the contract is in the process of being initialized.
|
||||
*/
|
||||
bool private _initializing;
|
||||
|
||||
/**
|
||||
* @dev Modifier to protect an initializer function from being invoked twice.
|
||||
*/
|
||||
modifier initializer() {
|
||||
require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
|
||||
|
||||
bool isTopLevelCall = !_initializing;
|
||||
if (isTopLevelCall) {
|
||||
_initializing = true;
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
_;
|
||||
|
||||
if (isTopLevelCall) {
|
||||
_initializing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Returns true if and only if the function is running in the constructor
|
||||
function _isConstructor() private view returns (bool) {
|
||||
// extcodesize checks the size of the code stored in an address, and
|
||||
// address returns the current address. Since the code is still not
|
||||
// deployed when running a constructor, any checks on its code size will
|
||||
// yield zero, making it an effective way to detect if a contract is
|
||||
// under construction or not.
|
||||
address self = address(this);
|
||||
uint256 cs;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { cs := extcodesize(self) }
|
||||
return cs == 0;
|
||||
}
|
||||
}
|
||||
83
contracts/proxy/Proxy.sol
Normal file
83
contracts/proxy/Proxy.sol
Normal file
@ -0,0 +1,83 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
/**
|
||||
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
|
||||
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
|
||||
* be specified by overriding the virtual {_implementation} function.
|
||||
*
|
||||
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
|
||||
* different contract through the {_delegate} function.
|
||||
*
|
||||
* The success and return data of the delegated call will be returned back to the caller of the proxy.
|
||||
*/
|
||||
abstract contract Proxy {
|
||||
/**
|
||||
* @dev Delegates the current call to `implementation`.
|
||||
*
|
||||
* This function does not return to its internall call site, it will return directly to the external caller.
|
||||
*/
|
||||
function _delegate(address implementation) internal {
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
// Copy msg.data. We take full control of memory in this inline assembly
|
||||
// block because it will not return to Solidity code. We overwrite the
|
||||
// Solidity scratch pad at memory position 0.
|
||||
calldatacopy(0, 0, calldatasize())
|
||||
|
||||
// Call the implementation.
|
||||
// out and outsize are 0 because we don't know the size yet.
|
||||
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
|
||||
|
||||
// Copy the returned data.
|
||||
returndatacopy(0, 0, returndatasize())
|
||||
|
||||
switch result
|
||||
// delegatecall returns 0 on error.
|
||||
case 0 { revert(0, returndatasize()) }
|
||||
default { return(0, returndatasize()) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
|
||||
* and {_fallback} should delegate.
|
||||
*/
|
||||
function _implementation() internal virtual view returns (address);
|
||||
|
||||
/**
|
||||
* @dev Delegates the current call to the address returned by `_implementation()`.
|
||||
*
|
||||
* This function does not return to its internall call site, it will return directly to the external caller.
|
||||
*/
|
||||
function _fallback() internal {
|
||||
_beforeFallback();
|
||||
_delegate(_implementation());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
|
||||
* function in the contract matches the call data.
|
||||
*/
|
||||
fallback () payable external {
|
||||
_fallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
|
||||
* is empty.
|
||||
*/
|
||||
receive () payable external {
|
||||
_fallback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
|
||||
* call, or as part of the Solidity `fallback` or `receive` functions.
|
||||
*
|
||||
* If overriden should call `super._beforeFallback()`.
|
||||
*/
|
||||
function _beforeFallback() internal virtual {
|
||||
}
|
||||
}
|
||||
77
contracts/proxy/ProxyAdmin.sol
Normal file
77
contracts/proxy/ProxyAdmin.sol
Normal file
@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../access/Ownable.sol";
|
||||
import "./TransparentUpgradeableProxy.sol";
|
||||
|
||||
/**
|
||||
* @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
|
||||
* explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
|
||||
*/
|
||||
contract ProxyAdmin is Ownable {
|
||||
|
||||
/**
|
||||
* @dev Returns the current implementation of `proxy`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - This contract must be the admin of `proxy`.
|
||||
*/
|
||||
function getProxyImplementation(TransparentUpgradeableProxy proxy) public view returns (address) {
|
||||
// We need to manually run the static call since the getter cannot be flagged as view
|
||||
// bytes4(keccak256("implementation()")) == 0x5c60da1b
|
||||
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
|
||||
require(success);
|
||||
return abi.decode(returndata, (address));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the current admin of `proxy`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - This contract must be the admin of `proxy`.
|
||||
*/
|
||||
function getProxyAdmin(TransparentUpgradeableProxy proxy) public view returns (address) {
|
||||
// We need to manually run the static call since the getter cannot be flagged as view
|
||||
// bytes4(keccak256("admin()")) == 0xf851a440
|
||||
(bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
|
||||
require(success);
|
||||
return abi.decode(returndata, (address));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Changes the admin of `proxy` to `newAdmin`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - This contract must be the current admin of `proxy`.
|
||||
*/
|
||||
function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public onlyOwner {
|
||||
proxy.changeAdmin(newAdmin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - This contract must be the admin of `proxy`.
|
||||
*/
|
||||
function upgrade(TransparentUpgradeableProxy proxy, address implementation) public onlyOwner {
|
||||
proxy.upgradeTo(implementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
|
||||
* {TransparentUpgradeableProxy-upgradeToAndCall}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - This contract must be the admin of `proxy`.
|
||||
*/
|
||||
function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable onlyOwner {
|
||||
proxy.upgradeToAndCall{value: msg.value}(implementation, data);
|
||||
}
|
||||
}
|
||||
26
contracts/proxy/README.adoc
Normal file
26
contracts/proxy/README.adoc
Normal file
@ -0,0 +1,26 @@
|
||||
= Proxies
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/proxy
|
||||
|
||||
This is a low-level set of contracts implementing the proxy pattern for upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page.
|
||||
|
||||
The abstract {Proxy} contract implements the core delegation functionality. If the concrete proxies that we provide below are not suitable, we encourage building on top of this base contract since it contains an assembly block that may be hard to get right.
|
||||
|
||||
Upgradeability is implemented in the {UpgradeableProxy} contract, although it provides only an internal upgrade interface. For an upgrade interface exposed externally to an admin, we provide {TransparentUpgradeableProxy}. Both of these contracts use the storage slots specified in https://eips.ethereum.org/EIPS/eip-1967[EIP1967] to avoid clashes with the storage of the implementation contract behind the proxy.
|
||||
|
||||
CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Truffle and Buidler.
|
||||
|
||||
== Core
|
||||
|
||||
{{Proxy}}
|
||||
|
||||
{{UpgradeableProxy}}
|
||||
|
||||
{{TransparentUpgradeableProxy}}
|
||||
|
||||
== Utilities
|
||||
|
||||
{{Initializable}}
|
||||
|
||||
{{ProxyAdmin}}
|
||||
153
contracts/proxy/TransparentUpgradeableProxy.sol
Normal file
153
contracts/proxy/TransparentUpgradeableProxy.sol
Normal file
@ -0,0 +1,153 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./UpgradeableProxy.sol";
|
||||
|
||||
/**
|
||||
* @dev This contract implements a proxy that is upgradeable by an admin.
|
||||
*
|
||||
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
|
||||
* clashing], which can potentially be used in an attack, this contract uses the
|
||||
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
|
||||
* things that go hand in hand:
|
||||
*
|
||||
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
|
||||
* that call matches one of the admin functions exposed by the proxy itself.
|
||||
* 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
|
||||
* implementation. If the admin tries to call a function on the implementation it will fail with an error that says
|
||||
* "admin cannot fallback to proxy target".
|
||||
*
|
||||
* These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
|
||||
* the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
|
||||
* to sudden errors when trying to call a function from the proxy implementation.
|
||||
*
|
||||
* Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
|
||||
* you should think of the `ProxyAdmin` instance as the real administrative inerface of your proxy.
|
||||
*/
|
||||
contract TransparentUpgradeableProxy is UpgradeableProxy {
|
||||
/**
|
||||
* @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
|
||||
* optionally initialized with `_data` as explained in {UpgradeableProxy-constructor}.
|
||||
*/
|
||||
constructor(address _logic, address _admin, bytes memory _data) public payable UpgradeableProxy(_logic, _data) {
|
||||
assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
|
||||
_setAdmin(_admin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Emitted when the admin account has changed.
|
||||
*/
|
||||
event AdminChanged(address previousAdmin, address newAdmin);
|
||||
|
||||
/**
|
||||
* @dev Storage slot with the admin of the contract.
|
||||
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
|
||||
* validated in the constructor.
|
||||
*/
|
||||
bytes32 private constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
|
||||
|
||||
/**
|
||||
* @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
|
||||
*/
|
||||
modifier ifAdmin() {
|
||||
if (msg.sender == _admin()) {
|
||||
_;
|
||||
} else {
|
||||
_fallback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the current admin.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
|
||||
*
|
||||
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
|
||||
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
|
||||
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
|
||||
*/
|
||||
function admin() external ifAdmin returns (address) {
|
||||
return _admin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the current implementation.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
|
||||
*
|
||||
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
|
||||
* https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
|
||||
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
|
||||
*/
|
||||
function implementation() external ifAdmin returns (address) {
|
||||
return _implementation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Changes the admin of the proxy.
|
||||
*
|
||||
* Emits an {AdminChanged} event.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
|
||||
*/
|
||||
function changeAdmin(address newAdmin) external ifAdmin {
|
||||
require(newAdmin != address(0), "TransparentUpgradeableProxy: new admin is the zero address");
|
||||
emit AdminChanged(_admin(), newAdmin);
|
||||
_setAdmin(newAdmin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrade the implementation of the proxy.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
|
||||
*/
|
||||
function upgradeTo(address newImplementation) external ifAdmin {
|
||||
_upgradeTo(newImplementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
|
||||
* by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
|
||||
* proxied contract.
|
||||
*
|
||||
* NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
|
||||
*/
|
||||
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
|
||||
_upgradeTo(newImplementation);
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool success,) = newImplementation.delegatecall(data);
|
||||
require(success);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the current admin.
|
||||
*/
|
||||
function _admin() internal view returns (address adm) {
|
||||
bytes32 slot = _ADMIN_SLOT;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
adm := sload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Stores a new address in the EIP1967 admin slot.
|
||||
*/
|
||||
function _setAdmin(address newAdmin) private {
|
||||
bytes32 slot = _ADMIN_SLOT;
|
||||
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
sstore(slot, newAdmin)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
|
||||
*/
|
||||
function _beforeFallback() internal override virtual {
|
||||
require(msg.sender != _admin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
|
||||
super._beforeFallback();
|
||||
}
|
||||
}
|
||||
80
contracts/proxy/UpgradeableProxy.sol
Normal file
80
contracts/proxy/UpgradeableProxy.sol
Normal file
@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./Proxy.sol";
|
||||
import "../utils/Address.sol";
|
||||
|
||||
/**
|
||||
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
|
||||
* implementation address that can be changed. This address is stored in storage in the location specified by
|
||||
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
|
||||
* implementation behind the proxy.
|
||||
*
|
||||
* Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see
|
||||
* {TransparentUpgradeableProxy}.
|
||||
*/
|
||||
contract UpgradeableProxy is Proxy {
|
||||
/**
|
||||
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
|
||||
*
|
||||
* If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
|
||||
* function call, and allows initializating the storage of the proxy like a Solidity constructor.
|
||||
*/
|
||||
constructor(address _logic, bytes memory _data) public payable {
|
||||
assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
|
||||
_setImplementation(_logic);
|
||||
if(_data.length > 0) {
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool success,) = _logic.delegatecall(_data);
|
||||
require(success);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Emitted when the implementation is upgraded.
|
||||
*/
|
||||
event Upgraded(address indexed implementation);
|
||||
|
||||
/**
|
||||
* @dev Storage slot with the address of the current implementation.
|
||||
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
|
||||
* validated in the constructor.
|
||||
*/
|
||||
bytes32 private constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
|
||||
|
||||
/**
|
||||
* @dev Returns the current implementation address.
|
||||
*/
|
||||
function _implementation() internal override view returns (address impl) {
|
||||
bytes32 slot = _IMPLEMENTATION_SLOT;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
impl := sload(slot)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Upgrades the proxy to a new implementation.
|
||||
*
|
||||
* Emits an {Upgraded} event.
|
||||
*/
|
||||
function _upgradeTo(address newImplementation) internal {
|
||||
_setImplementation(newImplementation);
|
||||
emit Upgraded(newImplementation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Stores a new address in the EIP1967 implementation slot.
|
||||
*/
|
||||
function _setImplementation(address newImplementation) private {
|
||||
require(Address.isContract(newImplementation), "UpgradeableProxy: new implementation is not a contract");
|
||||
|
||||
bytes32 slot = _IMPLEMENTATION_SLOT;
|
||||
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
sstore(slot, newImplementation)
|
||||
}
|
||||
}
|
||||
}
|
||||
413
contracts/token/ERC1155/ERC1155.sol
Normal file
413
contracts/token/ERC1155/ERC1155.sol
Normal file
@ -0,0 +1,413 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./IERC1155.sol";
|
||||
import "./IERC1155MetadataURI.sol";
|
||||
import "./IERC1155Receiver.sol";
|
||||
import "../../GSN/Context.sol";
|
||||
import "../../introspection/ERC165.sol";
|
||||
import "../../math/SafeMath.sol";
|
||||
import "../../utils/Address.sol";
|
||||
|
||||
/**
|
||||
*
|
||||
* @dev Implementation of the basic standard multi-token.
|
||||
* See https://eips.ethereum.org/EIPS/eip-1155
|
||||
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
|
||||
using SafeMath for uint256;
|
||||
using Address for address;
|
||||
|
||||
// Mapping from token ID to account balances
|
||||
mapping (uint256 => mapping(address => uint256)) private _balances;
|
||||
|
||||
// Mapping from account to operator approvals
|
||||
mapping (address => mapping(address => bool)) private _operatorApprovals;
|
||||
|
||||
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
|
||||
string private _uri;
|
||||
|
||||
/*
|
||||
* bytes4(keccak256('balanceOf(address,uint256)')) == 0x00fdd58e
|
||||
* bytes4(keccak256('balanceOfBatch(address[],uint256[])')) == 0x4e1273f4
|
||||
* bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
|
||||
* bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
|
||||
* bytes4(keccak256('safeTransferFrom(address,address,uint256,uint256,bytes)')) == 0xf242432a
|
||||
* bytes4(keccak256('safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)')) == 0x2eb2c2d6
|
||||
*
|
||||
* => 0x00fdd58e ^ 0x4e1273f4 ^ 0xa22cb465 ^
|
||||
* 0xe985e9c5 ^ 0xf242432a ^ 0x2eb2c2d6 == 0xd9b67a26
|
||||
*/
|
||||
bytes4 private constant _INTERFACE_ID_ERC1155 = 0xd9b67a26;
|
||||
|
||||
/*
|
||||
* bytes4(keccak256('uri(uint256)')) == 0x0e89341c
|
||||
*/
|
||||
bytes4 private constant _INTERFACE_ID_ERC1155_METADATA_URI = 0x0e89341c;
|
||||
|
||||
/**
|
||||
* @dev See {_setURI}.
|
||||
*/
|
||||
constructor (string memory uri) public {
|
||||
_setURI(uri);
|
||||
|
||||
// register the supported interfaces to conform to ERC1155 via ERC165
|
||||
_registerInterface(_INTERFACE_ID_ERC1155);
|
||||
|
||||
// register the supported interfaces to conform to ERC1155MetadataURI via ERC165
|
||||
_registerInterface(_INTERFACE_ID_ERC1155_METADATA_URI);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155MetadataURI-uri}.
|
||||
*
|
||||
* This implementation returns the same URI for *all* token types. It relies
|
||||
* on the token type ID substitution mechanism
|
||||
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
|
||||
*
|
||||
* Clients calling this function must replace the `\{id\}` substring with the
|
||||
* actual token type ID.
|
||||
*/
|
||||
function uri(uint256) external view override returns (string memory) {
|
||||
return _uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-balanceOf}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
*/
|
||||
function balanceOf(address account, uint256 id) public view override returns (uint256) {
|
||||
require(account != address(0), "ERC1155: balance query for the zero address");
|
||||
return _balances[id][account];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-balanceOfBatch}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `accounts` and `ids` must have the same length.
|
||||
*/
|
||||
function balanceOfBatch(
|
||||
address[] memory accounts,
|
||||
uint256[] memory ids
|
||||
)
|
||||
public
|
||||
view
|
||||
override
|
||||
returns (uint256[] memory)
|
||||
{
|
||||
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
|
||||
|
||||
uint256[] memory batchBalances = new uint256[](accounts.length);
|
||||
|
||||
for (uint256 i = 0; i < accounts.length; ++i) {
|
||||
require(accounts[i] != address(0), "ERC1155: batch balance query for the zero address");
|
||||
batchBalances[i] = _balances[ids[i]][accounts[i]];
|
||||
}
|
||||
|
||||
return batchBalances;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-setApprovalForAll}.
|
||||
*/
|
||||
function setApprovalForAll(address operator, bool approved) public virtual override {
|
||||
require(_msgSender() != operator, "ERC1155: setting approval status for self");
|
||||
|
||||
_operatorApprovals[_msgSender()][operator] = approved;
|
||||
emit ApprovalForAll(_msgSender(), operator, approved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-isApprovedForAll}.
|
||||
*/
|
||||
function isApprovedForAll(address account, address operator) public view override returns (bool) {
|
||||
return _operatorApprovals[account][operator];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-safeTransferFrom}.
|
||||
*/
|
||||
function safeTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
bytes memory data
|
||||
)
|
||||
public
|
||||
virtual
|
||||
override
|
||||
{
|
||||
require(to != address(0), "ERC1155: transfer to the zero address");
|
||||
require(
|
||||
from == _msgSender() || isApprovedForAll(from, _msgSender()),
|
||||
"ERC1155: caller is not owner nor approved"
|
||||
);
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data);
|
||||
|
||||
_balances[id][from] = _balances[id][from].sub(amount, "ERC1155: insufficient balance for transfer");
|
||||
_balances[id][to] = _balances[id][to].add(amount);
|
||||
|
||||
emit TransferSingle(operator, from, to, id, amount);
|
||||
|
||||
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {IERC1155-safeBatchTransferFrom}.
|
||||
*/
|
||||
function safeBatchTransferFrom(
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
public
|
||||
virtual
|
||||
override
|
||||
{
|
||||
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
|
||||
require(to != address(0), "ERC1155: transfer to the zero address");
|
||||
require(
|
||||
from == _msgSender() || isApprovedForAll(from, _msgSender()),
|
||||
"ERC1155: transfer caller is not owner nor approved"
|
||||
);
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
|
||||
|
||||
for (uint256 i = 0; i < ids.length; ++i) {
|
||||
uint256 id = ids[i];
|
||||
uint256 amount = amounts[i];
|
||||
|
||||
_balances[id][from] = _balances[id][from].sub(
|
||||
amount,
|
||||
"ERC1155: insufficient balance for transfer"
|
||||
);
|
||||
_balances[id][to] = _balances[id][to].add(amount);
|
||||
}
|
||||
|
||||
emit TransferBatch(operator, from, to, ids, amounts);
|
||||
|
||||
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets a new URI for all token types, by relying on the token type ID
|
||||
* substitution mechanism
|
||||
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
|
||||
*
|
||||
* By this mechanism, any occurrence of the `\{id\}` substring in either the
|
||||
* URI or any of the amounts in the JSON file at said URI will be replaced by
|
||||
* clients with the token type ID.
|
||||
*
|
||||
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
|
||||
* interpreted by clients as
|
||||
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
|
||||
* for token type ID 0x4cce0.
|
||||
*
|
||||
* See {uri}.
|
||||
*
|
||||
* Because these URIs cannot be meaningfully represented by the {URI} event,
|
||||
* this function emits no events.
|
||||
*/
|
||||
function _setURI(string memory newuri) internal virtual {
|
||||
_uri = newuri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Creates `amount` tokens of token type `id`, and assigns them to `account`.
|
||||
*
|
||||
* Emits a {TransferSingle} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual {
|
||||
require(account != address(0), "ERC1155: mint to the zero address");
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data);
|
||||
|
||||
_balances[id][account] = _balances[id][account].add(amount);
|
||||
emit TransferSingle(operator, address(0), account, id, amount);
|
||||
|
||||
_doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `ids` and `amounts` must have the same length.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual {
|
||||
require(to != address(0), "ERC1155: mint to the zero address");
|
||||
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
|
||||
|
||||
for (uint i = 0; i < ids.length; i++) {
|
||||
_balances[ids[i]][to] = amounts[i].add(_balances[ids[i]][to]);
|
||||
}
|
||||
|
||||
emit TransferBatch(operator, address(0), to, ids, amounts);
|
||||
|
||||
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Destroys `amount` tokens of token type `id` from `account`
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
* - `account` must have at least `amount` tokens of token type `id`.
|
||||
*/
|
||||
function _burn(address account, uint256 id, uint256 amount) internal virtual {
|
||||
require(account != address(0), "ERC1155: burn from the zero address");
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), "");
|
||||
|
||||
_balances[id][account] = _balances[id][account].sub(
|
||||
amount,
|
||||
"ERC1155: burn amount exceeds balance"
|
||||
);
|
||||
|
||||
emit TransferSingle(operator, account, address(0), id, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `ids` and `amounts` must have the same length.
|
||||
*/
|
||||
function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual {
|
||||
require(account != address(0), "ERC1155: burn from the zero address");
|
||||
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
|
||||
|
||||
address operator = _msgSender();
|
||||
|
||||
_beforeTokenTransfer(operator, account, address(0), ids, amounts, "");
|
||||
|
||||
for (uint i = 0; i < ids.length; i++) {
|
||||
_balances[ids[i]][account] = _balances[ids[i]][account].sub(
|
||||
amounts[i],
|
||||
"ERC1155: burn amount exceeds balance"
|
||||
);
|
||||
}
|
||||
|
||||
emit TransferBatch(operator, account, address(0), ids, amounts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Hook that is called before any token transfer. This includes minting
|
||||
* and burning, as well as batched variants.
|
||||
*
|
||||
* The same hook is called on both single and batched variants. For single
|
||||
* transfers, the length of the `id` and `amount` arrays will be 1.
|
||||
*
|
||||
* Calling conditions (for each `id` and `amount` pair):
|
||||
*
|
||||
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
|
||||
* of token type `id` will be transferred to `to`.
|
||||
* - When `from` is zero, `amount` tokens of token type `id` will be minted
|
||||
* for `to`.
|
||||
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
|
||||
* will be burned.
|
||||
* - `from` and `to` are never both zero.
|
||||
* - `ids` and `amounts` have the same, non-zero length.
|
||||
*
|
||||
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
|
||||
*/
|
||||
function _beforeTokenTransfer(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
internal virtual
|
||||
{ }
|
||||
|
||||
function _doSafeTransferAcceptanceCheck(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256 id,
|
||||
uint256 amount,
|
||||
bytes memory data
|
||||
)
|
||||
private
|
||||
{
|
||||
if (to.isContract()) {
|
||||
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
|
||||
if (response != IERC1155Receiver(to).onERC1155Received.selector) {
|
||||
revert("ERC1155: ERC1155Receiver rejected tokens");
|
||||
}
|
||||
} catch Error(string memory reason) {
|
||||
revert(reason);
|
||||
} catch {
|
||||
revert("ERC1155: transfer to non ERC1155Receiver implementer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _doSafeBatchTransferAcceptanceCheck(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
private
|
||||
{
|
||||
if (to.isContract()) {
|
||||
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (bytes4 response) {
|
||||
if (response != IERC1155Receiver(to).onERC1155BatchReceived.selector) {
|
||||
revert("ERC1155: ERC1155Receiver rejected tokens");
|
||||
}
|
||||
} catch Error(string memory reason) {
|
||||
revert(reason);
|
||||
} catch {
|
||||
revert("ERC1155: transfer to non ERC1155Receiver implementer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
|
||||
uint256[] memory array = new uint256[](1);
|
||||
array[0] = element;
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
31
contracts/token/ERC1155/ERC1155Burnable.sol
Normal file
31
contracts/token/ERC1155/ERC1155Burnable.sol
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./ERC1155.sol";
|
||||
|
||||
/**
|
||||
* @dev Extension of {ERC1155} that allows token holders to destroy both their
|
||||
* own tokens and those that they have been approved to use.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
abstract contract ERC1155Burnable is ERC1155 {
|
||||
function burn(address account, uint256 id, uint256 value) public virtual {
|
||||
require(
|
||||
account == _msgSender() || isApprovedForAll(account, _msgSender()),
|
||||
"ERC1155: caller is not owner nor approved"
|
||||
);
|
||||
|
||||
_burn(account, id, value);
|
||||
}
|
||||
|
||||
function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual {
|
||||
require(
|
||||
account == _msgSender() || isApprovedForAll(account, _msgSender()),
|
||||
"ERC1155: caller is not owner nor approved"
|
||||
);
|
||||
|
||||
_burnBatch(account, ids, values);
|
||||
}
|
||||
}
|
||||
18
contracts/token/ERC1155/ERC1155Holder.sol
Normal file
18
contracts/token/ERC1155/ERC1155Holder.sol
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./ERC1155Receiver.sol";
|
||||
|
||||
/**
|
||||
* @dev _Available since v3.1._
|
||||
*/
|
||||
contract ERC1155Holder is ERC1155Receiver {
|
||||
function onERC1155Received(address, address, uint256, uint256, bytes memory) public virtual override returns (bytes4) {
|
||||
return this.onERC1155Received.selector;
|
||||
}
|
||||
|
||||
function onERC1155BatchReceived(address, address, uint256[] memory, uint256[] memory, bytes memory) public virtual override returns (bytes4) {
|
||||
return this.onERC1155BatchReceived.selector;
|
||||
}
|
||||
}
|
||||
39
contracts/token/ERC1155/ERC1155Pausable.sol
Normal file
39
contracts/token/ERC1155/ERC1155Pausable.sol
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./ERC1155.sol";
|
||||
import "../../utils/Pausable.sol";
|
||||
|
||||
/**
|
||||
* @dev ERC1155 token with pausable token transfers, minting and burning.
|
||||
*
|
||||
* Useful for scenarios such as preventing trades until the end of an evaluation
|
||||
* period, or having an emergency switch for freezing all token transfers in the
|
||||
* event of a large bug.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
abstract contract ERC1155Pausable is ERC1155, Pausable {
|
||||
/**
|
||||
* @dev See {ERC1155-_beforeTokenTransfer}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the contract must not be paused.
|
||||
*/
|
||||
function _beforeTokenTransfer(
|
||||
address operator,
|
||||
address from,
|
||||
address to,
|
||||
uint256[] memory ids,
|
||||
uint256[] memory amounts,
|
||||
bytes memory data
|
||||
)
|
||||
internal virtual override
|
||||
{
|
||||
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
|
||||
|
||||
require(!paused(), "ERC1155Pausable: token transfer while paused");
|
||||
}
|
||||
}
|
||||
18
contracts/token/ERC1155/ERC1155Receiver.sol
Normal file
18
contracts/token/ERC1155/ERC1155Receiver.sol
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "./IERC1155Receiver.sol";
|
||||
import "../../introspection/ERC165.sol";
|
||||
|
||||
/**
|
||||
* @dev _Available since v3.1._
|
||||
*/
|
||||
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
|
||||
constructor() public {
|
||||
_registerInterface(
|
||||
ERC1155Receiver(0).onERC1155Received.selector ^
|
||||
ERC1155Receiver(0).onERC1155BatchReceived.selector
|
||||
);
|
||||
}
|
||||
}
|
||||
103
contracts/token/ERC1155/IERC1155.sol
Normal file
103
contracts/token/ERC1155/IERC1155.sol
Normal file
@ -0,0 +1,103 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.2;
|
||||
|
||||
import "../../introspection/IERC165.sol";
|
||||
|
||||
/**
|
||||
* @dev Required interface of an ERC1155 compliant contract, as defined in the
|
||||
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
interface IERC1155 is IERC165 {
|
||||
/**
|
||||
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
|
||||
*/
|
||||
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
|
||||
|
||||
/**
|
||||
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
|
||||
* transfers.
|
||||
*/
|
||||
event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);
|
||||
|
||||
/**
|
||||
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
|
||||
* `approved`.
|
||||
*/
|
||||
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
|
||||
|
||||
/**
|
||||
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
|
||||
*
|
||||
* If an {URI} event was emitted for `id`, the standard
|
||||
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
|
||||
* returned by {IERC1155MetadataURI-uri}.
|
||||
*/
|
||||
event URI(string value, uint256 indexed id);
|
||||
|
||||
/**
|
||||
* @dev Returns the amount of tokens of token type `id` owned by `account`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `account` cannot be the zero address.
|
||||
*/
|
||||
function balanceOf(address account, uint256 id) external view returns (uint256);
|
||||
|
||||
/**
|
||||
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `accounts` and `ids` must have the same length.
|
||||
*/
|
||||
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
|
||||
|
||||
/**
|
||||
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
|
||||
*
|
||||
* Emits an {ApprovalForAll} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `operator` cannot be the caller.
|
||||
*/
|
||||
function setApprovalForAll(address operator, bool approved) external;
|
||||
|
||||
/**
|
||||
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
|
||||
*
|
||||
* See {setApprovalForAll}.
|
||||
*/
|
||||
function isApprovedForAll(address account, address operator) external view returns (bool);
|
||||
|
||||
/**
|
||||
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
|
||||
*
|
||||
* Emits a {TransferSingle} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `to` cannot be the zero address.
|
||||
* - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
|
||||
* - `from` must have a balance of tokens of type `id` of at least `amount`.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
|
||||
|
||||
/**
|
||||
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
|
||||
*
|
||||
* Emits a {TransferBatch} event.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `ids` and `amounts` must have the same length.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
|
||||
* acceptance magic value.
|
||||
*/
|
||||
function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
|
||||
}
|
||||
21
contracts/token/ERC1155/IERC1155MetadataURI.sol
Normal file
21
contracts/token/ERC1155/IERC1155MetadataURI.sol
Normal file
@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.2;
|
||||
|
||||
import "./IERC1155.sol";
|
||||
|
||||
/**
|
||||
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
|
||||
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
interface IERC1155MetadataURI is IERC1155 {
|
||||
/**
|
||||
* @dev Returns the URI for token type `id`.
|
||||
*
|
||||
* If the `\{id\}` substring is present in the URI, it must be replaced by
|
||||
* clients with the actual token type ID.
|
||||
*/
|
||||
function uri(uint256 id) external view returns (string memory);
|
||||
}
|
||||
57
contracts/token/ERC1155/IERC1155Receiver.sol
Normal file
57
contracts/token/ERC1155/IERC1155Receiver.sol
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "../../introspection/IERC165.sol";
|
||||
|
||||
/**
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
interface IERC1155Receiver is IERC165 {
|
||||
|
||||
/**
|
||||
@dev Handles the receipt of a single ERC1155 token type. This function is
|
||||
called at the end of a `safeTransferFrom` after the balance has been updated.
|
||||
To accept the transfer, this must return
|
||||
`bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
|
||||
(i.e. 0xf23a6e61, or its own function selector).
|
||||
@param operator The address which initiated the transfer (i.e. msg.sender)
|
||||
@param from The address which previously owned the token
|
||||
@param id The ID of the token being transferred
|
||||
@param value The amount of tokens being transferred
|
||||
@param data Additional data with no specified format
|
||||
@return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
|
||||
*/
|
||||
function onERC1155Received(
|
||||
address operator,
|
||||
address from,
|
||||
uint256 id,
|
||||
uint256 value,
|
||||
bytes calldata data
|
||||
)
|
||||
external
|
||||
returns(bytes4);
|
||||
|
||||
/**
|
||||
@dev Handles the receipt of a multiple ERC1155 token types. This function
|
||||
is called at the end of a `safeBatchTransferFrom` after the balances have
|
||||
been updated. To accept the transfer(s), this must return
|
||||
`bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
|
||||
(i.e. 0xbc197c81, or its own function selector).
|
||||
@param operator The address which initiated the batch transfer (i.e. msg.sender)
|
||||
@param from The address which previously owned the token
|
||||
@param ids An array containing ids of each token being transferred (order and length must match values array)
|
||||
@param values An array containing amounts of each token being transferred (order and length must match ids array)
|
||||
@param data Additional data with no specified format
|
||||
@return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
|
||||
*/
|
||||
function onERC1155BatchReceived(
|
||||
address operator,
|
||||
address from,
|
||||
uint256[] calldata ids,
|
||||
uint256[] calldata values,
|
||||
bytes calldata data
|
||||
)
|
||||
external
|
||||
returns(bytes4);
|
||||
}
|
||||
37
contracts/token/ERC1155/README.adoc
Normal file
37
contracts/token/ERC1155/README.adoc
Normal file
@ -0,0 +1,37 @@
|
||||
= ERC 1155
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc1155
|
||||
|
||||
This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-1155[ERC1155 Multi Token Standard].
|
||||
|
||||
The EIP consists of three interfaces which fulfill different roles, found here as {IERC1155}, {IERC1155MetadataURI} and {IERC1155Receiver}.
|
||||
|
||||
{ERC1155} implements the mandatory {IERC1155} interface, as well as the optional extension {IERC1155MetadataURI}, by relying on the substitution mechanism to use the same URI for all token types, dramatically reducing gas costs.
|
||||
|
||||
Additionally there are multiple custom extensions, including:
|
||||
|
||||
* designation of addresses that can pause token transfers for all users ({ERC1155Pausable}).
|
||||
* destruction of own tokens ({ERC1155Burnable}).
|
||||
|
||||
NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC1155 (such as <<ERC1155-_mint-address-uint256-uint256-bytes-,`_mint`>>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc1155.adoc#Presets[ERC1155 Presets] (such as {ERC1155PresetMinterPauser}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts.
|
||||
|
||||
== Core
|
||||
|
||||
{{IERC1155}}
|
||||
|
||||
{{IERC1155MetadataURI}}
|
||||
|
||||
{{ERC1155}}
|
||||
|
||||
{{IERC1155Receiver}}
|
||||
|
||||
== Extensions
|
||||
|
||||
{{ERC1155Pausable}}
|
||||
|
||||
{{ERC1155Burnable}}
|
||||
|
||||
== Convenience
|
||||
|
||||
{{ERC1155Holder}}
|
||||
@ -12,7 +12,7 @@ import "../../utils/Address.sol";
|
||||
*
|
||||
* This implementation is agnostic to the way tokens are created. This means
|
||||
* that a supply mechanism has to be added in a derived contract using {_mint}.
|
||||
* For a generic mechanism see {ERC20MinterPauser}.
|
||||
* For a generic mechanism see {ERC20PresetMinterPauser}.
|
||||
*
|
||||
* TIP: For a detailed writeup see our guide
|
||||
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
|
||||
@ -258,9 +258,9 @@ contract ERC20 is Context, IERC20 {
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
|
||||
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
|
||||
*
|
||||
* This is internal function is equivalent to `approve`, and can be used to
|
||||
* This internal function is equivalent to `approve`, and can be used to
|
||||
* e.g. set automatic allowances for certain subsystems, etc.
|
||||
*
|
||||
* Emits an {Approval} event.
|
||||
|
||||
@ -104,28 +104,25 @@ abstract contract ERC20Snapshot is ERC20 {
|
||||
return snapshotted ? value : totalSupply();
|
||||
}
|
||||
|
||||
// _transfer, _mint and _burn are the only functions where the balances are modified, so it is there that the
|
||||
// snapshots are updated. Note that the update happens _before_ the balance change, with the pre-modified value.
|
||||
// The same is true for the total supply and _mint and _burn.
|
||||
function _transfer(address from, address to, uint256 value) internal virtual override {
|
||||
|
||||
// Update balance and/or total supply snapshots before the values are modified. This is implemented
|
||||
// in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations.
|
||||
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
|
||||
super._beforeTokenTransfer(from, to, amount);
|
||||
|
||||
if (from == address(0)) {
|
||||
// mint
|
||||
_updateAccountSnapshot(to);
|
||||
_updateTotalSupplySnapshot();
|
||||
} else if (to == address(0)) {
|
||||
// burn
|
||||
_updateAccountSnapshot(from);
|
||||
_updateTotalSupplySnapshot();
|
||||
} else {
|
||||
// transfer
|
||||
_updateAccountSnapshot(from);
|
||||
_updateAccountSnapshot(to);
|
||||
|
||||
super._transfer(from, to, value);
|
||||
}
|
||||
|
||||
function _mint(address account, uint256 value) internal virtual override {
|
||||
_updateAccountSnapshot(account);
|
||||
_updateTotalSupplySnapshot();
|
||||
|
||||
super._mint(account, value);
|
||||
}
|
||||
|
||||
function _burn(address account, uint256 value) internal virtual override {
|
||||
_updateAccountSnapshot(account);
|
||||
_updateTotalSupplySnapshot();
|
||||
|
||||
super._burn(account, value);
|
||||
}
|
||||
}
|
||||
|
||||
function _valueAt(uint256 snapshotId, Snapshots storage snapshots)
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
= ERC 20
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc20
|
||||
|
||||
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:erc20.adoc[ERC20 guide].
|
||||
TIP: For an overview of ERC20 tokens and a walk through on how to create a token contract read our xref:ROOT:erc20.adoc[ERC20 guide].
|
||||
|
||||
There a few core contracts that implement the behavior specified in the EIP:
|
||||
|
||||
@ -21,6 +24,8 @@ Finally, there are some utilities to interact with ERC20 contracts in various wa
|
||||
* {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 core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC20 (such as <<ERC20-_mint-address-uint256-,`_mint`>>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc20.adoc#Presets[ERC20 Presets] (such as {ERC20PresetMinterPauser}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts.
|
||||
|
||||
== Core
|
||||
|
||||
{{IERC20}}
|
||||
|
||||
@ -12,7 +12,7 @@ import "../../utils/Address.sol";
|
||||
* contract returns false). Tokens that return no value (and instead revert or
|
||||
* throw on failure) are also supported, non-reverting calls are assumed to be
|
||||
* successful.
|
||||
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
|
||||
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
|
||||
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
|
||||
*/
|
||||
library SafeERC20 {
|
||||
@ -27,6 +27,13 @@ library SafeERC20 {
|
||||
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Deprecated. This function has issues similar to the ones found in
|
||||
* {IERC20-approve}, and its usage is discouraged.
|
||||
*
|
||||
* Whenever possible, use {safeIncreaseAllowance} and
|
||||
* {safeDecreaseAllowance} instead.
|
||||
*/
|
||||
function safeApprove(IERC20 token, address spender, uint256 value) internal {
|
||||
// safeApprove should only be called when setting an initial allowance,
|
||||
// or when resetting it to zero. To increase and decrease it, use
|
||||
@ -56,19 +63,10 @@ library SafeERC20 {
|
||||
*/
|
||||
function _callOptionalReturn(IERC20 token, bytes memory data) private {
|
||||
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
|
||||
// we're implementing it ourselves.
|
||||
|
||||
// A Solidity high level call has three parts:
|
||||
// 1. The target address is checked to verify it contains contract code
|
||||
// 2. The call itself is made, and success asserted
|
||||
// 3. The return value is decoded, which in turn checks the size of the returned data.
|
||||
// solhint-disable-next-line max-line-length
|
||||
require(address(token).isContract(), "SafeERC20: call to non-contract");
|
||||
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool success, bytes memory returndata) = address(token).call(data);
|
||||
require(success, "SafeERC20: low-level call failed");
|
||||
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
|
||||
// the target address contains contract code and also asserts for success in the low-level call.
|
||||
|
||||
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
|
||||
if (returndata.length > 0) { // Return data is optional
|
||||
// solhint-disable-next-line max-line-length
|
||||
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
|
||||
|
||||
@ -10,8 +10,6 @@ import "./SafeERC20.sol";
|
||||
*
|
||||
* 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 {
|
||||
using SafeERC20 for IERC20;
|
||||
|
||||
@ -48,7 +48,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
string private _symbol;
|
||||
|
||||
// Optional mapping for token URIs
|
||||
mapping(uint256 => string) private _tokenURIs;
|
||||
mapping (uint256 => string) private _tokenURIs;
|
||||
|
||||
// Base URI
|
||||
string private _baseURI;
|
||||
@ -65,7 +65,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
|
||||
*
|
||||
* => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
|
||||
* 0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
|
||||
* 0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
|
||||
*/
|
||||
bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
|
||||
|
||||
@ -87,6 +87,9 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
*/
|
||||
bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
|
||||
|
||||
/**
|
||||
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
|
||||
*/
|
||||
constructor (string memory name, string memory symbol) public {
|
||||
_name = name;
|
||||
_symbol = symbol;
|
||||
@ -98,9 +101,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the balance of the specified address.
|
||||
* @param owner address to query the balance of
|
||||
* @return uint256 representing the amount owned by the passed address
|
||||
* @dev See {IERC721-balanceOf}.
|
||||
*/
|
||||
function balanceOf(address owner) public view override returns (uint256) {
|
||||
require(owner != address(0), "ERC721: balance query for the zero address");
|
||||
@ -109,60 +110,28 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the owner of the specified token ID.
|
||||
* @param tokenId uint256 ID of the token to query the owner of
|
||||
* @return address currently marked as the owner of the given token ID
|
||||
* @dev See {IERC721-ownerOf}.
|
||||
*/
|
||||
function ownerOf(uint256 tokenId) public view override returns (address) {
|
||||
return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the token name.
|
||||
* @return string representing the token name
|
||||
* @dev See {IERC721Metadata-name}.
|
||||
*/
|
||||
function name() public view override returns (string memory) {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the token symbol.
|
||||
* @return string representing the token symbol
|
||||
* @dev See {IERC721Metadata-symbol}.
|
||||
*/
|
||||
function symbol() public view override returns (string memory) {
|
||||
return _symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the URI for a given token ID. May return an empty string.
|
||||
*
|
||||
* If a base URI is set (via {_setBaseURI}), it is added as a prefix to the
|
||||
* token's own URI (via {_setTokenURI}).
|
||||
*
|
||||
* If there is a base URI but no token URI, the token's ID will be used as
|
||||
* its URI when appending it to the base URI. This pattern for autogenerated
|
||||
* token URIs can lead to large gas savings.
|
||||
*
|
||||
* .Examples
|
||||
* |===
|
||||
* |`_setBaseURI()` |`_setTokenURI()` |`tokenURI()`
|
||||
* | ""
|
||||
* | ""
|
||||
* | ""
|
||||
* | ""
|
||||
* | "token.uri/123"
|
||||
* | "token.uri/123"
|
||||
* | "token.uri/"
|
||||
* | "123"
|
||||
* | "token.uri/123"
|
||||
* | "token.uri/"
|
||||
* | ""
|
||||
* | "token.uri/<tokenId>"
|
||||
* |===
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `tokenId` must exist.
|
||||
* @dev See {IERC721Metadata-tokenURI}.
|
||||
*/
|
||||
function tokenURI(uint256 tokenId) public view override returns (string memory) {
|
||||
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
|
||||
@ -191,18 +160,14 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the token ID at a given index of the tokens list of the requested owner.
|
||||
* @param owner address owning the tokens list to be accessed
|
||||
* @param index uint256 representing the index to be accessed of the requested tokens list
|
||||
* @return uint256 token ID at the given index of the tokens list owned by the requested address
|
||||
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
|
||||
*/
|
||||
function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) {
|
||||
return _holderTokens[owner].at(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the total amount of tokens stored by the contract.
|
||||
* @return uint256 representing the total amount of tokens
|
||||
* @dev See {IERC721Enumerable-totalSupply}.
|
||||
*/
|
||||
function totalSupply() public view override returns (uint256) {
|
||||
// _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
|
||||
@ -210,10 +175,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the token ID at a given index of all the tokens in this contract
|
||||
* Reverts if the index is greater or equal to the total number of tokens.
|
||||
* @param index uint256 representing the index to be accessed of the tokens list
|
||||
* @return uint256 token ID at the given index of the tokens list
|
||||
* @dev See {IERC721Enumerable-tokenByIndex}.
|
||||
*/
|
||||
function tokenByIndex(uint256 index) public view override returns (uint256) {
|
||||
(uint256 tokenId, ) = _tokenOwners.at(index);
|
||||
@ -221,12 +183,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Approves another address to transfer the given token ID
|
||||
* The zero address indicates there is no approved address.
|
||||
* There can only be one approved address per token at a given time.
|
||||
* Can only be called by the token owner or an approved operator.
|
||||
* @param to address to be approved for the given token ID
|
||||
* @param tokenId uint256 ID of the token to be approved
|
||||
* @dev See {IERC721-approve}.
|
||||
*/
|
||||
function approve(address to, uint256 tokenId) public virtual override {
|
||||
address owner = ownerOf(tokenId);
|
||||
@ -240,10 +197,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the approved address for a token ID, or zero if no address set
|
||||
* Reverts if the token ID does not exist.
|
||||
* @param tokenId uint256 ID of the token to query the approval of
|
||||
* @return address currently approved for the given token ID
|
||||
* @dev See {IERC721-getApproved}.
|
||||
*/
|
||||
function getApproved(uint256 tokenId) public view override returns (address) {
|
||||
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
|
||||
@ -252,10 +206,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets or unsets the approval of a given operator
|
||||
* An operator is allowed to transfer all tokens of the sender on their behalf.
|
||||
* @param operator operator address to set the approval
|
||||
* @param approved representing the status of the approval to be set
|
||||
* @dev See {IERC721-setApprovalForAll}.
|
||||
*/
|
||||
function setApprovalForAll(address operator, bool approved) public virtual override {
|
||||
require(operator != _msgSender(), "ERC721: approve to caller");
|
||||
@ -265,22 +216,14 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells whether an operator is approved by a given owner.
|
||||
* @param owner owner address which you want to query the approval of
|
||||
* @param operator operator address which you want to query the approval of
|
||||
* @return bool whether the given operator is approved by the given owner
|
||||
* @dev See {IERC721-isApprovedForAll}.
|
||||
*/
|
||||
function isApprovedForAll(address owner, address operator) public view override returns (bool) {
|
||||
return _operatorApprovals[owner][operator];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Transfers the ownership of a given token ID to another address.
|
||||
* Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
|
||||
* Requires the msg.sender 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
|
||||
* @dev See {IERC721-transferFrom}.
|
||||
*/
|
||||
function transferFrom(address from, address to, uint256 tokenId) public virtual override {
|
||||
//solhint-disable-next-line max-line-length
|
||||
@ -290,31 +233,14 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Safely transfers the ownership of a given token ID to another address
|
||||
* If the target address is a contract, it must implement {IERC721Receiver-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 msg.sender 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
|
||||
* @dev See {IERC721-safeTransferFrom}.
|
||||
*/
|
||||
function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
|
||||
safeTransferFrom(from, to, tokenId, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Safely transfers the ownership of a given token ID to another address
|
||||
* If the target address is a contract, it must implement {IERC721Receiver-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
|
||||
* @dev See {IERC721-safeTransferFrom}.
|
||||
*/
|
||||
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
|
||||
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
|
||||
@ -322,16 +248,22 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 msg.sender 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
|
||||
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
|
||||
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
|
||||
*
|
||||
* `_data` is additional data, it has no specified format and it is sent in call to `to`.
|
||||
*
|
||||
* This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
|
||||
* implement alternative mechanisms to perform token transfer, such as signature-based.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `from` cannot be the zero address.
|
||||
* - `to` cannot be the zero address.
|
||||
* - `tokenId` token must exist and be owned by `from`.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
|
||||
_transfer(from, to, tokenId);
|
||||
@ -339,20 +271,23 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether the specified token exists.
|
||||
* @param tokenId uint256 ID of the token to query the existence of
|
||||
* @return bool whether the token exists
|
||||
* @dev Returns whether `tokenId` exists.
|
||||
*
|
||||
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
|
||||
*
|
||||
* Tokens start existing when they are minted (`_mint`),
|
||||
* and stop existing when they are burned (`_burn`).
|
||||
*/
|
||||
function _exists(uint256 tokenId) internal view returns (bool) {
|
||||
return _tokenOwners.contains(tokenId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns whether the given spender can transfer a given token ID.
|
||||
* @param spender address of the spender to query
|
||||
* @param tokenId uint256 ID of the token to be transferred
|
||||
* @return bool whether the msg.sender is approved for the given token ID,
|
||||
* is an operator of the owner, or is the owner of the token
|
||||
* @dev Returns whether `spender` is allowed to manage `tokenId`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `tokenId` must exist.
|
||||
*/
|
||||
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
|
||||
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
|
||||
@ -361,29 +296,22 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
* @dev Safely mints `tokenId` and transfers it to `to`.
|
||||
*
|
||||
* Requirements:
|
||||
d*
|
||||
* - `tokenId` must not exist.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function _safeMint(address to, uint256 tokenId) internal virtual {
|
||||
_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
|
||||
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
|
||||
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
|
||||
*/
|
||||
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
|
||||
_mint(to, tokenId);
|
||||
@ -391,10 +319,16 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to mint a new token.
|
||||
* Reverts if the given token ID already exists.
|
||||
* @param to The address that will own the minted token
|
||||
* @param tokenId uint256 ID of the token to be minted
|
||||
* @dev Mints `tokenId` and transfers it to `to`.
|
||||
*
|
||||
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `tokenId` must not exist.
|
||||
* - `to` cannot be the zero address.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function _mint(address to, uint256 tokenId) internal virtual {
|
||||
require(to != address(0), "ERC721: mint to the zero address");
|
||||
@ -410,9 +344,14 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to burn a specific token.
|
||||
* Reverts if the token does not exist.
|
||||
* @param tokenId uint256 ID of the token being burned
|
||||
* @dev Destroys `tokenId`.
|
||||
* The approval is cleared when the token is burned.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `tokenId` must exist.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function _burn(uint256 tokenId) internal virtual {
|
||||
address owner = ownerOf(tokenId);
|
||||
@ -435,11 +374,15 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @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
|
||||
* @dev Transfers `tokenId` from `from` to `to`.
|
||||
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `to` cannot be the zero address.
|
||||
* - `tokenId` token must be owned by `from`.
|
||||
*
|
||||
* Emits a {Transfer} event.
|
||||
*/
|
||||
function _transfer(address from, address to, uint256 tokenId) internal virtual {
|
||||
require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
|
||||
@ -459,13 +402,11 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function to set the token URI for a given token.
|
||||
* @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
|
||||
*
|
||||
* Reverts if the token ID does not exist.
|
||||
* Requirements:
|
||||
*
|
||||
* TIP: If all token IDs share a prefix (for example, if your URIs look like
|
||||
* `https://api.myproject.com/token/<id>`), use {_setBaseURI} to store
|
||||
* it and save gas.
|
||||
* - `tokenId` must exist.
|
||||
*/
|
||||
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
|
||||
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
|
||||
@ -497,28 +438,15 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
if (!to.isContract()) {
|
||||
return true;
|
||||
}
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool success, bytes memory returndata) = to.call(abi.encodeWithSelector(
|
||||
bytes memory returndata = to.functionCall(abi.encodeWithSelector(
|
||||
IERC721Receiver(to).onERC721Received.selector,
|
||||
_msgSender(),
|
||||
from,
|
||||
tokenId,
|
||||
_data
|
||||
));
|
||||
if (!success) {
|
||||
if (returndata.length > 0) {
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
let returndata_size := mload(returndata)
|
||||
revert(add(32, returndata), returndata_size)
|
||||
}
|
||||
} else {
|
||||
revert("ERC721: transfer to non ERC721Receiver implementer");
|
||||
}
|
||||
} else {
|
||||
bytes4 retval = abi.decode(returndata, (bytes4));
|
||||
return (retval == _ERC721_RECEIVED);
|
||||
}
|
||||
), "ERC721: transfer to non ERC721Receiver implementer");
|
||||
bytes4 retval = abi.decode(returndata, (bytes4));
|
||||
return (retval == _ERC721_RECEIVED);
|
||||
}
|
||||
|
||||
function _approve(address to, uint256 tokenId) private {
|
||||
@ -532,11 +460,12 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
|
||||
*
|
||||
* Calling conditions:
|
||||
*
|
||||
* - when `from` and `to` are both non-zero, ``from``'s `tokenId` will be
|
||||
* - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
|
||||
* transferred to `to`.
|
||||
* - when `from` is zero, `tokenId` will be minted for `to`.
|
||||
* - when `to` is zero, ``from``'s `tokenId` will be burned.
|
||||
* - `from` and `to` are never both zero.
|
||||
* - When `from` is zero, `tokenId` will be minted for `to`.
|
||||
* - When `to` is zero, ``from``'s `tokenId` will be burned.
|
||||
* - `from` cannot be the zero address.
|
||||
* - `to` cannot be the zero address.
|
||||
*
|
||||
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
|
||||
*/
|
||||
|
||||
@ -11,8 +11,11 @@ import "./ERC721.sol";
|
||||
*/
|
||||
abstract contract ERC721Burnable is Context, ERC721 {
|
||||
/**
|
||||
* @dev Burns a specific ERC721 token.
|
||||
* @param tokenId uint256 id of the ERC721 token to be burned.
|
||||
* @dev Burns `tokenId`. See {ERC721-_burn}.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The caller must own `tokenId` or be an approved operator.
|
||||
*/
|
||||
function burn(uint256 tokenId) public virtual {
|
||||
//solhint-disable-next-line max-line-length
|
||||
|
||||
@ -4,7 +4,19 @@ pragma solidity ^0.6.0;
|
||||
|
||||
import "./IERC721Receiver.sol";
|
||||
|
||||
/**
|
||||
* @dev Implementation of the {IERC721Receiver} interface.
|
||||
*
|
||||
* Accepts all token transfers.
|
||||
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
|
||||
*/
|
||||
contract ERC721Holder is IERC721Receiver {
|
||||
|
||||
/**
|
||||
* @dev See {IERC721Receiver-onERC721Received}.
|
||||
*
|
||||
* Always returns `IERC721Receiver.onERC721Received.selector`.
|
||||
*/
|
||||
function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
|
||||
return this.onERC721Received.selector;
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import "../../introspection/IERC165.sol";
|
||||
*/
|
||||
interface IERC721 is IERC165 {
|
||||
/**
|
||||
* @dev Emitted when `tokenId` token is transfered from `from` to `to`.
|
||||
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
|
||||
*/
|
||||
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
|
||||
|
||||
@ -43,7 +43,8 @@ interface IERC721 is IERC165 {
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `from`, `to` cannot be zero.
|
||||
* - `from` cannot be the zero address.
|
||||
* - `to` cannot be the zero address.
|
||||
* - `tokenId` token must exist and be owned by `from`.
|
||||
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
|
||||
@ -59,7 +60,8 @@ interface IERC721 is IERC165 {
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `from`, `to` cannot be zero.
|
||||
* - `from` cannot be the zero address.
|
||||
* - `to` cannot be the zero address.
|
||||
* - `tokenId` token must be owned by `from`.
|
||||
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
|
||||
*
|
||||
@ -115,7 +117,8 @@ interface IERC721 is IERC165 {
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `from`, `to` cannot be zero.
|
||||
* - `from` cannot be the zero address.
|
||||
* - `to` cannot be the zero address.
|
||||
* - `tokenId` token must exist and be owned by `from`.
|
||||
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
|
||||
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
|
||||
|
||||
@ -7,21 +7,16 @@ pragma solidity ^0.6.0;
|
||||
* @dev Interface for any contract that wants to support safeTransfers
|
||||
* from ERC721 asset contracts.
|
||||
*/
|
||||
abstract contract IERC721Receiver {
|
||||
interface IERC721Receiver {
|
||||
/**
|
||||
* @notice Handle the receipt of an NFT
|
||||
* @dev The ERC721 smart contract calls this function on the recipient
|
||||
* after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
|
||||
* otherwise the caller will revert the transaction. The selector to be
|
||||
* returned can be obtained as `this.onERC721Received.selector`. This
|
||||
* function MAY throw to revert and reject the transfer.
|
||||
* Note: the ERC721 contract address is always the message sender.
|
||||
* @param operator The address which called `safeTransferFrom` function
|
||||
* @param from The address which previously owned the token
|
||||
* @param tokenId The NFT identifier which is being transferred
|
||||
* @param data Additional data with no specified format
|
||||
* @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
|
||||
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
|
||||
* by `operator` from `from`, this function is called.
|
||||
*
|
||||
* It must return its Solidity selector to confirm the token transfer.
|
||||
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
|
||||
*
|
||||
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
|
||||
*/
|
||||
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
|
||||
public virtual returns (bytes4);
|
||||
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data)
|
||||
external returns (bytes4);
|
||||
}
|
||||
|
||||
@ -1,20 +1,24 @@
|
||||
= ERC 721
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc721
|
||||
|
||||
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:erc721.adoc[ERC721 guide].
|
||||
TIP: For a walk through on how to create an ERC721 token read our xref:ROOT:erc721.adoc[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. However, all three are implemented in {ERC721}.
|
||||
|
||||
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:
|
||||
|
||||
Additionally there are multiple custom extensions, including:
|
||||
|
||||
* designation of addresses that can pause token transfers for all users ({ERC721Pausable}).
|
||||
* destruction of own tokens ({ERC721Burnable}).
|
||||
|
||||
NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC721 (such as <<ERC721-_mint-address-uint256-,`_mint`>>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc721.adoc#Presets[ERC721 Presets] (such as {ERC721PresetMinterPauserAutoId}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts.
|
||||
|
||||
|
||||
== Core
|
||||
|
||||
{{IERC721}}
|
||||
|
||||
@ -491,13 +491,13 @@ contract ERC777 is Context, IERC777, IERC20 {
|
||||
*
|
||||
* Calling conditions:
|
||||
*
|
||||
* - when `from` and `to` are both non-zero, ``from``'s `tokenId` will be
|
||||
* transferred to `to`.
|
||||
* - when `from` is zero, `tokenId` will be minted for `to`.
|
||||
* - when `to` is zero, ``from``'s `tokenId` will be burned.
|
||||
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
|
||||
* will be to transferred to `to`.
|
||||
* - when `from` is zero, `amount` tokens will be minted for `to`.
|
||||
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
|
||||
* - `from` and `to` are never both zero.
|
||||
*
|
||||
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
|
||||
*/
|
||||
function _beforeTokenTransfer(address operator, address from, address to, uint256 tokenId) internal virtual { }
|
||||
function _beforeTokenTransfer(address operator, address from, address to, uint256 amount) internal virtual { }
|
||||
}
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
= ERC 777
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc777
|
||||
|
||||
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:erc777.adoc[ERC777 guide].
|
||||
TIP: For an overview of ERC777 tokens and a walk through on how to create a token contract read our xref:ROOT:erc777.adoc[ERC777 guide].
|
||||
|
||||
The token behavior itself is implemented in the core contracts: {IERC777}, {ERC777}.
|
||||
|
||||
|
||||
@ -24,14 +24,14 @@ library Address {
|
||||
* ====
|
||||
*/
|
||||
function isContract(address account) internal view returns (bool) {
|
||||
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
|
||||
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
|
||||
// for accounts without code, i.e. `keccak256('')`
|
||||
bytes32 codehash;
|
||||
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
|
||||
// This method relies in extcodesize, which returns 0 for contracts in
|
||||
// construction, since the code is only stored at the end of the
|
||||
// constructor execution.
|
||||
|
||||
uint256 size;
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly { codehash := extcodehash(account) }
|
||||
return (codehash != accountHash && codehash != 0x0);
|
||||
assembly { size := extcodesize(account) }
|
||||
return size > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,4 +57,85 @@ library Address {
|
||||
(bool success, ) = recipient.call{ value: amount }("");
|
||||
require(success, "Address: unable to send value, recipient may have reverted");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Performs a Solidity function call using a low level `call`. A
|
||||
* plain`call` is an unsafe replacement for a function call: use this
|
||||
* function instead.
|
||||
*
|
||||
* If `target` reverts with a revert reason, it is bubbled up by this
|
||||
* function (like regular Solidity function calls).
|
||||
*
|
||||
* Returns the raw returned data. To convert to the expected return value,
|
||||
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `target` must be a contract.
|
||||
* - calling `target` with `data` must not revert.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
|
||||
return functionCall(target, data, "Address: low-level call failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
|
||||
* `errorMessage` as a fallback revert reason when `target` reverts.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
|
||||
return _functionCallWithValue(target, data, 0, errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
|
||||
* but also transferring `value` wei to `target`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - the calling contract must have an ETH balance of at least `value`.
|
||||
* - the called Solidity function must be `payable`.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
|
||||
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
|
||||
* with `errorMessage` as a fallback revert reason when `target` reverts.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
|
||||
require(address(this).balance >= value, "Address: insufficient balance for call");
|
||||
return _functionCallWithValue(target, data, value, errorMessage);
|
||||
}
|
||||
|
||||
function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
|
||||
require(isContract(target), "Address: call to non-contract");
|
||||
|
||||
// solhint-disable-next-line avoid-low-level-calls
|
||||
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
|
||||
if (success) {
|
||||
return returndata;
|
||||
} else {
|
||||
// Look for revert reason and bubble it up if present
|
||||
if (returndata.length > 0) {
|
||||
// The easiest way to bubble the revert reason is using memory via assembly
|
||||
|
||||
// solhint-disable-next-line no-inline-assembly
|
||||
assembly {
|
||||
let returndata_size := mload(returndata)
|
||||
revert(add(32, returndata), returndata_size)
|
||||
}
|
||||
} else {
|
||||
revert(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,6 +54,6 @@ library Create2 {
|
||||
bytes32 _data = keccak256(
|
||||
abi.encodePacked(bytes1(0xff), deployer, salt, bytecodeHash)
|
||||
);
|
||||
return address(bytes20(_data << 96));
|
||||
return address(uint256(_data));
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +42,10 @@ contract Pausable is Context {
|
||||
|
||||
/**
|
||||
* @dev Modifier to make a function callable only when the contract is not paused.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The contract must not be paused.
|
||||
*/
|
||||
modifier whenNotPaused() {
|
||||
require(!_paused, "Pausable: paused");
|
||||
@ -50,6 +54,10 @@ contract Pausable is Context {
|
||||
|
||||
/**
|
||||
* @dev Modifier to make a function callable only when the contract is paused.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The contract must be paused.
|
||||
*/
|
||||
modifier whenPaused() {
|
||||
require(_paused, "Pausable: not paused");
|
||||
@ -58,6 +66,10 @@ contract Pausable is Context {
|
||||
|
||||
/**
|
||||
* @dev Triggers stopped state.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The contract must not be paused.
|
||||
*/
|
||||
function _pause() internal virtual whenNotPaused {
|
||||
_paused = true;
|
||||
@ -66,6 +78,10 @@ contract Pausable is Context {
|
||||
|
||||
/**
|
||||
* @dev Returns to normal state.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - The contract must be paused.
|
||||
*/
|
||||
function _unpause() internal virtual whenPaused {
|
||||
_paused = false;
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
= Utilities
|
||||
|
||||
[.readme-notice]
|
||||
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils
|
||||
|
||||
Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives.
|
||||
|
||||
Security tools include:
|
||||
|
||||
* {Pausable}: provides a simple way to halt activity in your contracts (often in reponse to an external threat).
|
||||
* {Pausable}: provides a simple way to halt activity in your contracts (often in response to an external threat).
|
||||
* {ReentrancyGuard}: protects you from https://blog.openzeppelin.com/reentrancy-after-istanbul/[reentrant calls].
|
||||
|
||||
The {Address}, {Arrays} and {Strings} libraries provide more operations related to these native data types, while {SafeCast} adds ways to safely convert between the different signed and unsigned numeric types.
|
||||
|
||||
@ -19,16 +19,24 @@ pragma solidity ^0.6.0;
|
||||
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
|
||||
*/
|
||||
contract ReentrancyGuard {
|
||||
bool private _notEntered;
|
||||
// Booleans are more expensive than uint256 or any type that takes up a full
|
||||
// word because each write operation emits an extra SLOAD to first read the
|
||||
// slot's contents, replace the bits taken up by the boolean, and then write
|
||||
// back. This is the compiler's defense against contract upgrades and
|
||||
// pointer aliasing, and it cannot be disabled.
|
||||
|
||||
// The values being non-zero value makes deployment a bit more expensive,
|
||||
// but in exchange the refund on every call to nonReentrant will be lower in
|
||||
// amount. Since refunds are capped to a percentage of the total
|
||||
// transaction's gas, it is best to keep them low in cases like this one, to
|
||||
// increase the likelihood of the full refund coming into effect.
|
||||
uint256 private constant _NOT_ENTERED = 1;
|
||||
uint256 private constant _ENTERED = 2;
|
||||
|
||||
uint256 private _status;
|
||||
|
||||
constructor () internal {
|
||||
// Storing an initial non-zero value makes deployment a bit more
|
||||
// expensive, but in exchange the refund on every call to nonReentrant
|
||||
// will be lower in amount. Since refunds are capped to a percetange of
|
||||
// the total transaction's gas, it is best to keep them low in cases
|
||||
// like this one, to increase the likelihood of the full refund coming
|
||||
// into effect.
|
||||
_notEntered = true;
|
||||
_status = _NOT_ENTERED;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,15 +48,15 @@ contract ReentrancyGuard {
|
||||
*/
|
||||
modifier nonReentrant() {
|
||||
// On the first call to nonReentrant, _notEntered will be true
|
||||
require(_notEntered, "ReentrancyGuard: reentrant call");
|
||||
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
|
||||
|
||||
// Any calls to nonReentrant after this point will fail
|
||||
_notEntered = false;
|
||||
_status = _ENTERED;
|
||||
|
||||
_;
|
||||
|
||||
// By storing the original value once again, a refund is triggered (see
|
||||
// https://eips.ethereum.org/EIPS/eip-2200)
|
||||
_notEntered = true;
|
||||
_status = _NOT_ENTERED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,10 @@ pragma solidity ^0.6.0;
|
||||
|
||||
|
||||
/**
|
||||
* @dev Wrappers over Solidity's uintXX casting operators with added overflow
|
||||
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
|
||||
* checks.
|
||||
*
|
||||
* Downcasting from uint256 in Solidity does not revert on overflow. This can
|
||||
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
|
||||
* easily result in undesired exploitation or bugs, since developers usually
|
||||
* assume that overflows raise errors. `SafeCast` restores this intuition by
|
||||
* reverting the transaction when such an operation overflows.
|
||||
@ -15,8 +15,8 @@ pragma solidity ^0.6.0;
|
||||
* Using this library instead of the unchecked operations eliminates an entire
|
||||
* class of bugs, so it's recommended to use it always.
|
||||
*
|
||||
* Can be combined with {SafeMath} to extend it to smaller types, by performing
|
||||
* all math on `uint256` and then downcasting.
|
||||
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
|
||||
* all math on `uint256` and `int256` and then downcasting.
|
||||
*/
|
||||
library SafeCast {
|
||||
|
||||
@ -107,6 +107,96 @@ library SafeCast {
|
||||
return uint256(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the downcasted int128 from int256, reverting on
|
||||
* overflow (when the input is less than smallest int128 or
|
||||
* greater than largest int128).
|
||||
*
|
||||
* Counterpart to Solidity's `int128` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - input must fit into 128 bits
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function toInt128(int256 value) internal pure returns (int128) {
|
||||
require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
|
||||
return int128(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the downcasted int64 from int256, reverting on
|
||||
* overflow (when the input is less than smallest int64 or
|
||||
* greater than largest int64).
|
||||
*
|
||||
* Counterpart to Solidity's `int64` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - input must fit into 64 bits
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function toInt64(int256 value) internal pure returns (int64) {
|
||||
require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
|
||||
return int64(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the downcasted int32 from int256, reverting on
|
||||
* overflow (when the input is less than smallest int32 or
|
||||
* greater than largest int32).
|
||||
*
|
||||
* Counterpart to Solidity's `int32` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - input must fit into 32 bits
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function toInt32(int256 value) internal pure returns (int32) {
|
||||
require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
|
||||
return int32(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the downcasted int16 from int256, reverting on
|
||||
* overflow (when the input is less than smallest int16 or
|
||||
* greater than largest int16).
|
||||
*
|
||||
* Counterpart to Solidity's `int16` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - input must fit into 16 bits
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function toInt16(int256 value) internal pure returns (int16) {
|
||||
require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
|
||||
return int16(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the downcasted int8 from int256, reverting on
|
||||
* overflow (when the input is less than smallest int8 or
|
||||
* greater than largest int8).
|
||||
*
|
||||
* Counterpart to Solidity's `int8` operator.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - input must fit into 8 bits.
|
||||
*
|
||||
* _Available since v3.1._
|
||||
*/
|
||||
function toInt8(int256 value) internal pure returns (int8) {
|
||||
require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
|
||||
return int8(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Converts an unsigned uint256 into a signed int256.
|
||||
*
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
.{{contract.name}}
|
||||
{{/unless}}
|
||||
{{#each modifiers}}
|
||||
* {xref-{{slug fullName~}} }[`++{{name}}({{args.names}})++`]
|
||||
* {xref-{{slug anchor~}} }[`++{{name}}({{args.names}})++`]
|
||||
{{/each}}
|
||||
|
||||
{{/each}}
|
||||
@ -39,7 +39,7 @@
|
||||
.{{contract.name}}
|
||||
{{/unless}}
|
||||
{{#each functions}}
|
||||
* {xref-{{slug fullName~}} }[`++{{name}}({{args.names}})++`]
|
||||
* {xref-{{slug anchor~}} }[`++{{name}}({{args.names}})++`]
|
||||
{{/each}}
|
||||
|
||||
{{/each}}
|
||||
@ -56,7 +56,7 @@
|
||||
.{{contract.name}}
|
||||
{{/unless}}
|
||||
{{#each events}}
|
||||
* {xref-{{slug fullName~}} }[`++{{name}}({{args.names}})++`]
|
||||
* {xref-{{slug anchor~}} }[`++{{name}}({{args.names}})++`]
|
||||
{{/each}}
|
||||
|
||||
{{/each}}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
*** xref:erc20-supply.adoc[Creating Supply]
|
||||
** xref:erc721.adoc[ERC721]
|
||||
** xref:erc777.adoc[ERC777]
|
||||
** xref:erc1155.adoc[ERC1155]
|
||||
|
||||
* xref:gsn.adoc[Gas Station Network]
|
||||
** xref:gsn-strategies.adoc[Strategies]
|
||||
|
||||
@ -11,6 +11,8 @@ OpenZeppelin provides xref:api:access.adoc#Ownable[`Ownable`] for implementing o
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/MyContract.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||
@ -46,7 +48,7 @@ While the simplicity of _ownership_ can be useful for simple systems or quick pr
|
||||
|
||||
In essence, we will be defining multiple _roles_, each allowed to perform different sets of actions. An account may have, for example, 'moderator', 'minter' or 'admin' roles, which you will then check for instead of simply using `onlyOwner`. Separately, you will be able to define rules for how accounts can be granted a role, have it revoked, and more.
|
||||
|
||||
Most of software development uses access control systems that are role-based: some users are regular users, some may be supervisors or managers, and a few will often have administrative privileges.
|
||||
Most software uses access control systems that are role-based: some users are regular users, some may be supervisors or managers, and a few will often have administrative privileges.
|
||||
|
||||
[[using-access-control]]
|
||||
=== Using `AccessControl`
|
||||
@ -58,6 +60,8 @@ Here's a simple example of using `AccessControl` in an xref:tokens.adoc#ERC20[`E
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/MyToken.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
@ -88,6 +92,8 @@ Let's augment our ERC20 token example by also defining a 'burner' role, which le
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/MyToken.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
@ -119,18 +125,20 @@ So clean! By splitting concerns this way, more granular levels of permission may
|
||||
[[granting-and-revoking]]
|
||||
=== Granting and Revoking Roles
|
||||
|
||||
The ERC20 token example above uses `\_setupRole`, an `internal` function that is useful when programmatically asigning roles (such as during construction). But what if we later want to grant the 'minter' role to additional accounts?
|
||||
The ERC20 token example above uses `_setupRole`, an `internal` function that is useful when programmatically assigning roles (such as during construction). But what if we later want to grant the 'minter' role to additional accounts?
|
||||
|
||||
By default, **accounts with a role cannot grant it or revoke it from other accounts**: all having a role does is making the `hasRole` check pass. To grant and revoke roles dynamically, you will need help from the _role's admin_.
|
||||
|
||||
Every role has an associated admin role, which grants permission to call the `grantRole` and `revokeRole` functions. A role can be granted or revoked by using these if the calling account has the corresponding admin role. Multiple roles may have the same admin role to make management easier. A role's admin can even be the same role itself, which would cause accounts with that role to be able to also grant and revoke it.
|
||||
|
||||
This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also provides an easy way to manage simpler applications. `AccessControl` includes a special role, called `DEFAULT_ADMIN_ROLE`, which acts as the **default admin role for all roles**. An account with this role will be able to manage any other role, unless `\_setRoleAdmin` is used to select a new admin role.
|
||||
This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also provides an easy way to manage simpler applications. `AccessControl` includes a special role, called `DEFAULT_ADMIN_ROLE`, which acts as the **default admin role for all roles**. An account with this role will be able to manage any other role, unless `_setRoleAdmin` is used to select a new admin role.
|
||||
|
||||
Let's take a look at the ERC20 token example, this time taking advantage of the default admin role:
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/MyToken.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
@ -160,7 +168,7 @@ contract MyToken is ERC20, AccessControl {
|
||||
|
||||
Note that, unlike the previous examples, no accounts are granted the 'minter' or 'burner' roles. However, because those roles' admin role is the default admin role, and _that_ role was granted to `msg.sender`, that same account can call `grantRole` to give minting or burning permission, and `revokeRole` to remove it.
|
||||
|
||||
Dynamic role allocation is a often a desirable property, for example in systems where trust in a participant may vary over time. It can also be used to support use cases such as https://en.wikipedia.org/wiki/Know_your_customer[KYC], where the list of role-bearers may not be known up-front, or may be prohibitively expensive to include in a single transaction.
|
||||
Dynamic role allocation is often a desirable property, for example in systems where trust in a participant may vary over time. It can also be used to support use cases such as https://en.wikipedia.org/wiki/Know_your_customer[KYC], where the list of role-bearers may not be known up-front, or may be prohibitively expensive to include in a single transaction.
|
||||
|
||||
[[querying-privileged-accounts]]
|
||||
=== Querying Privileged Accounts
|
||||
|
||||
@ -16,4 +16,4 @@ Removed contracts are still available on the v2.5 release of OpenZeppelin Contra
|
||||
$ npm install @openzeppelin/contracts@v2.5
|
||||
```
|
||||
|
||||
Refer to the xref:2.x@contracts:api:utils.adoc[v2.x documentation] when working with them.
|
||||
Refer to the xref:2.x@contracts:api:drafts.adoc[v2.x documentation] when working with them.
|
||||
|
||||
149
docs/modules/ROOT/pages/erc1155.adoc
Normal file
149
docs/modules/ROOT/pages/erc1155.adoc
Normal file
@ -0,0 +1,149 @@
|
||||
= ERC1155
|
||||
|
||||
ERC1155 is a novel token standard that aims to take the best from previous standards to create a xref:tokens.adoc#different-kinds-of-tokens[*fungibility-agnostic*] and *gas-efficient* xref:tokens.adoc#but_first_coffee_a_primer_on_token_contracts[token contract].
|
||||
|
||||
TIP: ERC1155 draws ideas from all of xref:erc20.adoc[ERC20], xref:721.adoc[ERC721], and xref:erc777.adoc[ERC777]. If you're unfamiliar with those standards, head to their guides before moving on.
|
||||
|
||||
[[multi-token-standard]]
|
||||
== Multi Token Standard
|
||||
|
||||
The distinctive feature of ERC1155 is that it uses a single smart contract to represent multiple tokens at once. This is why its xref:api:token/ERC1155.adoc#IERC1155-balanceOf-address-uint256-[`balanceOf`] function differs from ERC20's and ERC777's: it has an additional `id` argument for the identifier of the token that you want to query the balance of.
|
||||
|
||||
This is similar to how ERC721 does things, but in that standard a token `id` has no concept of balance: each token is non-fungible and exists or doesn't. The ERC721 xref:api:token/ERC721.adoc#IERC721-balanceOf-address-[`balanceOf`] function refers to _how many different tokens_ an account has, not how many of each. On the other hand, in ERC1155 accounts have a distinct balance for each token `id`, and non-fungible tokens are implemented by simply minting a single one of them.
|
||||
|
||||
This approach leads to massive gas savings for projects that require multiple tokens. Instead of deploying a new contract for each token type, a single ERC1155 token contract can hold the entire system state, reducing deployment costs and complexity.
|
||||
|
||||
[[batch-operations]]
|
||||
== Batch Operations
|
||||
|
||||
Because all state is held in a single contract, it is possible to operate over multiple tokens in a single transaction very efficiently. The standard provides two functions, xref:api:token/ERC1155.adoc#IERC1155-balanceOfBatch-address---uint256---[`balanceOfBatch`] and xref:api:token/ERC1155.adoc#IERC1155-safeBatchTransferFrom-address-address-uint256---uint256---bytes-[`safeBatchTransferFrom`], that make querying multiple balances and transferring multiple tokens simpler and less gas-intensive.
|
||||
|
||||
In the spirit of the standard, we've also included batch operations in the non-standard functions, such as xref:api:token/ERC1155.adoc#ERC1155-_mintBatch-address-uint256---uint256---bytes-[`_mintBatch`].
|
||||
|
||||
== Constructing an ERC1155 Token Contract
|
||||
|
||||
We'll use ERC1155 to track multiple items in our game, which will each have their own unique attributes. We mint all items to the deployer of the contract, which we can later transfer to players. Players are free to keep their tokens or trade them with other people as they see fit, as they would any other asset on the blockchain!
|
||||
|
||||
For simplicity we will mint all items in the constructor but you could add minting functionality to the contract to mint on demand to players.
|
||||
|
||||
TIP: For an overview of minting mechanisms check out xref:erc20-supply.adoc[Creating ERC20 Supply].
|
||||
|
||||
Here's what a contract for tokenized items might look like:
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/GameItems.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
|
||||
|
||||
contract GameItems is ERC1155 {
|
||||
uint256 public constant GOLD = 0;
|
||||
uint256 public constant SILVER = 1;
|
||||
uint256 public constant THORS_HAMMER = 2;
|
||||
uint256 public constant SWORD = 3;
|
||||
uint256 public constant SHIELD = 4;
|
||||
|
||||
constructor() public ERC1155("https://game.example/api/item/{1}.json") {
|
||||
_mint(msg.sender, GOLD, 10**18, "");
|
||||
_mint(msg.sender, SILVER, 10**27, "");
|
||||
_mint(msg.sender, THORS_HAMMER, 1, "");
|
||||
_mint(msg.sender, SWORD, 10**9, "");
|
||||
_mint(msg.sender, SHIELD, 10**9, "");
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Note that for our Game Items, Gold is a fungible token whilst Thor's Hammer is a non-fungible token as we minted only one.
|
||||
|
||||
The xref:api:token/ERC1155.adoc#ERC1155[`ERC1155`] contract includes the optional extension xref:api:token/ERC1155.adoc#IERC1155MetadataURI[`IERC1155MetadataURI`]. That's where the xref:api:token/ERC1155.adoc#IERC1155MetadataURI-uri-uint256-[`uri`] function comes from: we use it to retrieve the metadata uri.
|
||||
|
||||
Also note that, unlike ERC20, ERC1155 lacks a `decimals` field, since each token is distinct and cannot be partitioned.
|
||||
|
||||
Once deployed, we will be able to query the deployer’s balance:
|
||||
[source,javascript]
|
||||
----
|
||||
> gameItems.balanceOf(deployerAddress,3)
|
||||
1000000000
|
||||
----
|
||||
|
||||
We can transfer items to player accounts:
|
||||
[source,javascript]
|
||||
----
|
||||
> gameItems.safeTransferFrom(deployerAddress, playerAddress, 2, 1, "0x0")
|
||||
> gameItems.balanceOf(playerAddress, 2)
|
||||
1
|
||||
> gameItems.balanceOf(deployerAddress, 2)
|
||||
0
|
||||
----
|
||||
|
||||
We can also batch transfer items to player accounts and get the balance of batches:
|
||||
[source,javascript]
|
||||
----
|
||||
> gameItems.safeBatchTransferFrom(deployerAddress, playerAddress, [0,1,3,4], [50,100,1,1], "0x0")
|
||||
> gameItems.balanceOfBatch([playerAddress,playerAddress,playerAddress,playerAddress,playerAddress], [0,1,2,3,4])
|
||||
[50,100,1,1,1]
|
||||
----
|
||||
|
||||
The metadata uri can be obtained:
|
||||
|
||||
[source,javascript]
|
||||
----
|
||||
> gameItems.uri(2)
|
||||
"https://game.example/api/item/{id}.json"
|
||||
----
|
||||
|
||||
The `uri` can include the string `++{id}++` which clients must replace with the actual token ID, in lowercase hexadecimal (with no 0x prefix) and leading zero padded to 64 hex characters.
|
||||
|
||||
For token ID `2` and uri `++https://game.example/api/item/{id}.json++` clients would replace `++{id}++` with `0000000000000000000000000000000000000000000000000000000000000002` to retrieve JSON at `https://game.example/api/item/0000000000000000000000000000000000000000000000000000000000000002.json`.
|
||||
|
||||
The JSON document for token ID 2 might look something like:
|
||||
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"name": "Thor's hammer",
|
||||
"description": "Mjölnir, the legendary hammer of the Norse god of thunder.",
|
||||
"image": "https://game.example/item-id-8u5h2m.png",
|
||||
"strength": 20
|
||||
}
|
||||
----
|
||||
|
||||
For more information about the metadata JSON Schema, check out the https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md#erc-1155-metadata-uri-json-schema[ERC-1155 Metadata URI JSON Schema].
|
||||
|
||||
NOTE: you'll notice that the item's information is included in the metadata, but that information isn't on-chain! So a game developer could change the underlying metadata, changing the rules of the game!
|
||||
|
||||
[[sending-to-contracts]]
|
||||
== Sending Tokens to Contracts
|
||||
|
||||
A key difference when using xref:api:token/ERC1155.adoc#IERC1155-safeTransferFrom-address-address-uint256-uint256-bytes-[`safeTransferFrom`] is that token transfers to other contracts may revert with the following message:
|
||||
|
||||
[source,text]
|
||||
----
|
||||
ERC1155: transfer to non ERC1155Receiver implementer
|
||||
----
|
||||
|
||||
This is a good thing! It means that the recipient contract has not registered itself as aware of the ERC1155 protocol, so transfers to it are disabled to *prevent tokens from being locked forever*. As an example, https://etherscan.io/token/0xa74476443119A942dE498590Fe1f2454d7D4aC0d?a=0xa74476443119A942dE498590Fe1f2454d7D4aC0d[the Golem contract currently holds over 350k `GNT` tokens], worth multiple tens of thousands of dollars, and lacks methods to get them out of there. This has happened to virtually every ERC20-backed project, usually due to user error.
|
||||
|
||||
In order for our contract to receive ERC1155 tokens we can inherit from the convenience contract xref:api:token/ERC1155.adoc#ERC1155Holder[`ERC1155Holder`] which handles the registering for us. Though we need to remember to implement functionality to allow tokens to be transferred out of our contract:
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/MyContract.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC1155/ERC1155Holder.sol";
|
||||
|
||||
contract MyContract is ERC1155Holder {
|
||||
}
|
||||
----
|
||||
|
||||
We can also implement more complex scenarios using the xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155Received-address-address-uint256-uint256-bytes-[`onERC1155Received`] and xref:api:token/ERC1155.adoc#IERC1155Receiver-onERC1155BatchReceived-address-address-uint256---uint256---bytes-[`onERC1155BatchReceived`] functions.
|
||||
|
||||
[[Presets]]
|
||||
== Preset ERC1155 contract
|
||||
A preset ERC1155 is available, xref:api:presets#ERC1155PresetMinterPauser[`ERC1155PresetMinterPauser`]. It is preset to allow for token minting (create) - including batch minting, stop all token transfers (pause) and allow holders to burn (destroy) their tokens. The contract uses xref:access-control.adoc[Access Control] to control access to the minting and pausing functionality. The account that deploys the contract will be granted the minter and pauser roles, as well as the default admin role.
|
||||
|
||||
This contract is ready to deploy without having to write any Solidity code. It can be used as-is for quick prototyping and testing, but is also suitable for production environments.
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
In this guide you will learn how to create an ERC20 token with a custom supply mechanism. We will showcase two idiomatic ways to use OpenZeppelin Contracts for this purpose that you will be able to apply to your smart contract development practice.
|
||||
|
||||
The standard interface implemented by tokens built on Ethereum is called ERC20, and Contracts includes a widely used implementation of it: the aptly named xref:api:token/ERC20.adoc[`ERC20`] contract. This contract, like the standard itself, is quite simple and bare-bones. In fact, if you try deploy an instance of `ERC20` as-is it will be quite literally useless... it will have no supply! What use is a token with no supply?
|
||||
The standard interface implemented by tokens built on Ethereum is called ERC20, and Contracts includes a widely used implementation of it: the aptly named xref:api:token/ERC20.adoc[`ERC20`] contract. This contract, like the standard itself, is quite simple and bare-bones. In fact, if you try to deploy an instance of `ERC20` as-is it will be quite literally useless... it will have no supply! What use is a token with no supply?
|
||||
|
||||
The way that supply is created is not defined in the ERC20 document. Every token is free to experiment with their own mechanisms, ranging from the most decentralized to the most centralized, from the most naive to the most researched, and more.
|
||||
|
||||
@ -57,18 +57,18 @@ As we can see, `_mint` makes it super easy to do this correctly.
|
||||
[[modularizing-the-mechanism]]
|
||||
== Modularizing the Mechanism
|
||||
|
||||
There is one supply mechanism already included in Contracts: `ERC20DeployReady`. This is a generic mechanism in which a set of accounts is assigned the `minter` role, granting them the permission to call a `mint` function, an external version of `_mint`.
|
||||
There is one supply mechanism already included in Contracts: `ERC20PresetMinterPauser`. This is a generic mechanism in which a set of accounts is assigned the `minter` role, granting them the permission to call a `mint` function, an external version of `_mint`.
|
||||
|
||||
This can be used for centralized minting, where an externally owned account (i.e. someone with a pair of cryptographic keys) decides how much supply to create and to whom. There are very legitimate use cases for this mechanism, such as https://medium.com/reserve-currency/why-another-stablecoin-866f774afede#3aea[traditional asset-backed stablecoins].
|
||||
This can be used for centralized minting, where an externally owned account (i.e. someone with a pair of cryptographic keys) decides how much supply to create and for whom. There are very legitimate use cases for this mechanism, such as https://medium.com/reserve-currency/why-another-stablecoin-866f774afede#3aea[traditional asset-backed stablecoins].
|
||||
|
||||
The accounts with the minter role don't need to be externally owned, though, and can just as well be smart contracts that implement a trustless mechanism. We can in fact implement the same behavior as the previous section.
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
contract MinerRewardMinter {
|
||||
ERC20MinterPauser _token;
|
||||
ERC20PresetMinterPauser _token;
|
||||
|
||||
constructor(ERC20MinterPauser token) public {
|
||||
constructor(ERC20PresetMinterPauser token) public {
|
||||
_token = token;
|
||||
}
|
||||
|
||||
@ -78,16 +78,16 @@ contract MinerRewardMinter {
|
||||
}
|
||||
----
|
||||
|
||||
This contract, when initialized with an `ERC20DeployReady` instance, will result in exactly the same behavior implemented in the previous section. What is interesting about using `ERC20DeployReady` is that we can easily combine multiple supply mechanisms by assigning the role to multiple contracts, and moreover that we can do this dynamically.
|
||||
This contract, when initialized with an `ERC20PresetMinterPauser` instance, and granted the `minter` role for that contract, will result in exactly the same behavior implemented in the previous section. What is interesting about using `ERC20PresetMinterPauser` is that we can easily combine multiple supply mechanisms by assigning the role to multiple contracts, and moreover that we can do this dynamically.
|
||||
|
||||
TIP: To learn more about roles and permissioned systems, head to our xref:access-control.adoc[Access Control guide].
|
||||
|
||||
[[automating-the-reward]]
|
||||
== Automating the Reward
|
||||
|
||||
Additionally to `_mint`, `ERC20` provides other internal functions that can be used or extended, such as xref:api:token/ERC20.adoc#ERC20-_transfer-address-address-uint256-[`_transfer`]. This function implements token transfers and is used by `ERC20`, so it can be used to trigger functionality automatically. This is something that can't be done with the `ERC20Mintable` approach.
|
||||
So far our supply mechanisms were triggered manually, but `ERC20` also allows us to extend the core functionality of the token through the xref:api:token/ERC20.adoc#ERC20-_beforeTokenTransfer-address-address-uint256-[`_beforeTokenTransfer`] hook (see xref:extending-contracts.adoc#using-hooks[Using Hooks]).
|
||||
|
||||
Adding to our previous supply mechanism, we can use this to mint a miner reward for every token transfer that is included in the blockchain.
|
||||
Adding to the supply mechanism from previous sections, we can use this hook to mint a miner reward for every token transfer that is included in the blockchain.
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
@ -98,16 +98,14 @@ contract ERC20WithAutoMinerReward is ERC20 {
|
||||
_mint(block.coinbase, 1000);
|
||||
}
|
||||
|
||||
function _transfer(address from, address to, uint256 value) internal override {
|
||||
function _beforeTokenTransfer(address from, address to, uint256 value) internal virtual override {
|
||||
_mintMinerReward();
|
||||
super._transfer(from, to, value);
|
||||
super._beforeTokenTransfer(from, to, value);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
Note how we override `_transfer` to first mint the miner reward and then run the original implementation by calling `super._transfer`. This last step is very important to preserve the original semantics of ERC20 transfers.
|
||||
|
||||
[[wrapping-up]]
|
||||
== Wrapping Up
|
||||
|
||||
We've seen two ways to implement ERC20 supply mechanisms: internally through `_mint`, and externally through `ERC20Mintable`. Hopefully this has helped you understand how to use OpenZeppelin and some of the design principles behind it, and you can apply them to your own smart contracts.
|
||||
We've seen two ways to implement ERC20 supply mechanisms: internally through `_mint`, and externally through `ERC20PresetMinterPauser`. Hopefully this has helped you understand how to use OpenZeppelin and some of the design principles behind it, and you can apply them to your own smart contracts.
|
||||
|
||||
@ -13,12 +13,14 @@ Here's what our GLD token might look like.
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/GLDToken.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||
|
||||
contract GLDToken is ERC20 {
|
||||
constructor(uint256 initialSupply) ERC20("Gold", "GLD") public {
|
||||
constructor(uint256 initialSupply) public ERC20("Gold", "GLD") {
|
||||
_mint(msg.sender, initialSupply);
|
||||
}
|
||||
}
|
||||
@ -33,18 +35,18 @@ That's it! Once deployed, we will be able to query the deployer's balance:
|
||||
[source,javascript]
|
||||
----
|
||||
> GLDToken.balanceOf(deployerAddress)
|
||||
1000
|
||||
1000000000000000000000
|
||||
----
|
||||
|
||||
We can also xref:api:token/ERC20.adoc#IERC20-transfer-address-uint256-[transfer] these tokens to other accounts:
|
||||
|
||||
[source,javascript]
|
||||
----
|
||||
> GLDToken.transfer(otherAddress, 300)
|
||||
> GLDToken.transfer(otherAddress, 300000000000000000000)
|
||||
> GLDToken.balanceOf(otherAddress)
|
||||
300
|
||||
300000000000000000000
|
||||
> GLDToken.balanceOf(deployerAddress)
|
||||
700
|
||||
700000000000000000000
|
||||
----
|
||||
|
||||
[[a-note-on-decimals]]
|
||||
@ -67,3 +69,9 @@ So if you want to send `5` tokens using a token contract with 18 decimals, the t
|
||||
```solidity
|
||||
transfer(recipient, 5 * 10^18);
|
||||
```
|
||||
|
||||
[[Presets]]
|
||||
== Preset ERC20 contract
|
||||
A preset ERC20 is available, xref:api:presets#ERC20PresetMinterPauser[`ERC20PresetMinterPauser`]. It is preset to allow for token minting (create), stop all token transfers (pause) and allow holders to burn (destroy) their tokens. The contract uses xref:access-control.adoc[Access Control] to control access to the minting and pausing functionality. The account that deploys the contract will be granted the minter and pauser roles, as well as the default admin role.
|
||||
|
||||
This contract is ready to deploy without having to write any Solidity code. It can be used as-is for quick prototyping and testing, but is also suitable for production environments.
|
||||
|
||||
@ -2,16 +2,18 @@
|
||||
|
||||
We've discussed how you can make a _fungible_ token using xref:erc20.adoc[ERC20], but what if not all tokens are alike? This comes up in situations like *real estate* or *collectibles*, where some items are valued more than others, due to their usefulness, rarity, etc. ERC721 is a standard for representing ownership of xref:tokens.adoc#different-kinds-of-tokens[_non-fungible_ tokens], that is, where each token is unique.
|
||||
|
||||
ERC721 is a more complex standard than ERC20, with multiple optional extensions, and is split accross a number of contracts. The OpenZeppelin Contracts provide flexibility regarding how these are combined, along with custom useful extensions. Check out the xref:api:token/ERC721.adoc[API Reference] to learn more about these.
|
||||
ERC721 is a more complex standard than ERC20, with multiple optional extensions, and is split across a number of contracts. The OpenZeppelin Contracts provide flexibility regarding how these are combined, along with custom useful extensions. Check out the xref:api:token/ERC721.adoc[API Reference] to learn more about these.
|
||||
|
||||
== Constructing an ERC721 Token Contract
|
||||
|
||||
We'll use ERC721 to track items in our game, which will each have their own unique attributes. Whenever one is to be awarded to a player, it will be minted and sent to them. Players are free to keep their token or trade it with other people as they see fit, as they would any other asset on the blockchain!
|
||||
We'll use ERC721 to track items in our game, which will each have their own unique attributes. Whenever one is to be awarded to a player, it will be minted and sent to them. Players are free to keep their token or trade it with other people as they see fit, as they would any other asset on the blockchain! Please note any account can call `awardItem` to mint items. To restrict what accounts can mint items we can add xref:access-control.adoc[Access Control].
|
||||
|
||||
Here's what a contract for tokenized items might look like:
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/GameItem.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
@ -21,10 +23,12 @@ contract GameItem is ERC721 {
|
||||
using Counters for Counters.Counter;
|
||||
Counters.Counter private _tokenIds;
|
||||
|
||||
constructor() ERC721("GameItem", "ITM") public {
|
||||
}
|
||||
constructor() public ERC721("GameItem", "ITM") {}
|
||||
|
||||
function awardItem(address player, string memory tokenURI) public returns (uint256) {
|
||||
function awardItem(address player, string memory tokenURI)
|
||||
public
|
||||
returns (uint256)
|
||||
{
|
||||
_tokenIds.increment();
|
||||
|
||||
uint256 newItemId = _tokenIds.current();
|
||||
@ -45,7 +49,9 @@ New items can be created:
|
||||
[source,javascript]
|
||||
----
|
||||
> gameItem.awardItem(playerAddress, "https://game.example/item-id-8u5h2m.json")
|
||||
7
|
||||
Transaction successful. Transaction hash: 0x...
|
||||
Events emitted:
|
||||
- Transfer(0x0000000000000000000000000000000000000000, playerAddress, 7)
|
||||
----
|
||||
|
||||
And the owner and metadata of each item queried:
|
||||
@ -73,3 +79,9 @@ This `tokenURI` should resolve to a JSON document that might look something like
|
||||
For more information about the `tokenURI` metadata JSON Schema, check out the https://eips.ethereum.org/EIPS/eip-721[ERC721 specification].
|
||||
|
||||
NOTE: you'll notice that the item's information is included in the metadata, but that information isn't on-chain! So a game developer could change the underlying metadata, changing the rules of the game! If you'd like to put all item information on-chain, you can extend ERC721 to do so (though it will be rather costly). You could also leverage IPFS to store the tokenURI information, but these techniques are out of the scope of this overview guide.
|
||||
|
||||
[[Presets]]
|
||||
== Preset ERC721 contract
|
||||
A preset ERC721 is available, xref:api:presets#ERC721PresetMinterPauserAutoId[`ERC721PresetMinterPauserAutoId`]. It is preset to allow for token minting (create) with token ID and URI auto generation, stop all token transfers (pause) and allow holders to burn (destroy) their tokens. The contract uses xref:access-control.adoc[Access Control] to control access to the minting and pausing functionality. The account that deploys the contract will be granted the minter and pauser roles, as well as the default admin role.
|
||||
|
||||
This contract is ready to deploy without having to write any Solidity code. It can be used as-is for quick prototyping and testing, but is also suitable for production environments.
|
||||
|
||||
@ -18,17 +18,16 @@ We will replicate the `GLD` example of the xref:erc20.adoc#constructing-an-erc20
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/GLDToken.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC777/ERC777.sol";
|
||||
|
||||
contract GLDToken is ERC777 {
|
||||
constructor(
|
||||
uint256 initialSupply,
|
||||
address[] memory defaultOperators
|
||||
)
|
||||
ERC777("Gold", "GLD", defaultOperators)
|
||||
constructor(uint256 initialSupply, address[] memory defaultOperators)
|
||||
public
|
||||
ERC777("Gold", "GLD", defaultOperators)
|
||||
{
|
||||
_mint(msg.sender, initialSupply, "", "");
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ Inheritance is often used to add the parent contract's functionality to your own
|
||||
For example, imagine you want to change xref:api:access.adoc#AccessControl[`AccessControl`] so that xref:api:access.adoc#AccessControl-revokeRole-bytes32-address-[`revokeRole`] can no longer be called. This can be achieved using overrides:
|
||||
|
||||
```solidity
|
||||
// contracts/ModifiedAccessControl.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
@ -44,6 +46,8 @@ Here is a modified version of xref:api:access.adoc#AccessControl[`AccessControl`
|
||||
|
||||
|
||||
```solidity
|
||||
// contracts/ModifiedAccessControl.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
@ -62,7 +66,7 @@ contract ModifiedAccessControl is AccessControl {
|
||||
|
||||
The `super.revokeRole` statement at the end will invoke ``AccessControl``'s original version of `revokeRole`, the same code that would've run if there were no overrides in place.
|
||||
|
||||
NOTE: As of v3.0.0, `view` functions are not `virtual` in OpenZeppelin, and therefore cannot be overriden. We're considering https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2154[lifting this restriction] in an upcoming release. Let us know if this is something you care about!
|
||||
NOTE: As of v3.0.0, `view` functions are not `virtual` in OpenZeppelin, and therefore cannot be overridden. We're considering https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2154[lifting this restriction] in an upcoming release. Let us know if this is something you care about!
|
||||
|
||||
[[using-hooks]]
|
||||
== Using Hooks
|
||||
@ -92,6 +96,9 @@ contract ERC20WithSafeTransfer is ERC20 {
|
||||
function _validRecipient(address to) private view returns (bool) {
|
||||
...
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Using hooks this way leads to cleaner and safer code, without having to rely on a deep understanding of the parent's internals.
|
||||
@ -100,7 +107,7 @@ Using hooks this way leads to cleaner and safer code, without having to rely on
|
||||
====
|
||||
Hooks are a new feature of OpenZeppelin Contracts v3.0.0, and we're eager to learn how you plan to use them!
|
||||
|
||||
So far, the only available hook is `_beforeTransferHook`, in all of xref:api:token/ERC20.adoc#ERC20-_beforeTokenTransfer-address-address-uint256-[`ERC20`], xref:api:token/ERC721.adoc#ERC721-_beforeTokenTransfer-address-address-uint256-[ERC721] and xref:api:token/ERC777.adoc#ERC777-_beforeTokenTransfer-address-address-address-uint256-[ERC777]. If you have ideas for new hooks, let us know!
|
||||
So far, the only available hook is `_beforeTransferHook`, in all of xref:api:token/ERC20.adoc#ERC20-_beforeTokenTransfer-address-address-uint256-[`ERC20`], xref:api:token/ERC721.adoc#ERC721-_beforeTokenTransfer-address-address-uint256-[`ERC721`], xref:api:token/ERC777.adoc#ERC777-_beforeTokenTransfer-address-address-address-uint256-[`ERC777`] and xref:api:token/ERC1155.adoc#ERC1155-_beforeTokenTransfer-address-address-address-uint256---uint256---bytes-[`ERC1155`]. If you have ideas for new hooks, let us know!
|
||||
====
|
||||
|
||||
=== Rules of Hooks
|
||||
@ -121,3 +128,4 @@ contract MyToken is ERC20 {
|
||||
}
|
||||
```
|
||||
That's it! Enjoy simpler code using hooks!
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ On the other hand, you need to have a backend server, microservice, or lambda fu
|
||||
|
||||
`GSNRecipientSignature` decides whether or not to accept the relayed call based on the included signature.
|
||||
|
||||
The `acceptRelayedCall` implementation recovers the address from the signature of the relayed call parameters in `approvalData` and compares to the trusted signer.
|
||||
The `acceptRelayedCall` implementation recovers the address from the signature of the relayed call parameters in `approvalData` and compares it to the trusted signer.
|
||||
If the included signature matches the trusted signer, the relayed call is approved.
|
||||
On the other hand, when the included signature doesn't match the trusted signer, the relayed call gets rejected with an error code of `INVALID_SIGNER`.
|
||||
|
||||
@ -106,6 +106,10 @@ Your GSN recipient contract needs to inherit from `GSNRecipientERC20Fee` along w
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/MyContract.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/GSN/GSNRecipientERC20Fee.sol";
|
||||
import "@openzeppelin/contracts/access/AccessControl.sol";
|
||||
|
||||
|
||||
@ -34,17 +34,17 @@ First, RelayHub will ask your recipient contract if it wants to receive a relaye
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
function acceptRelayedCall(
|
||||
address relay,
|
||||
address from,
|
||||
bytes calldata encodedFunction,
|
||||
uint256 transactionFee,
|
||||
uint256 gasPrice,
|
||||
uint256 gasLimit,
|
||||
uint256 nonce,
|
||||
bytes calldata approvalData,
|
||||
uint256 maxPossibleCharge
|
||||
) external view returns (uint256, bytes memory);
|
||||
function acceptRelayedCall(
|
||||
address relay,
|
||||
address from,
|
||||
bytes calldata encodedFunction,
|
||||
uint256 transactionFee,
|
||||
uint256 gasPrice,
|
||||
uint256 gasLimit,
|
||||
uint256 nonce,
|
||||
bytes calldata approvalData,
|
||||
uint256 maxPossibleCharge
|
||||
) external view returns (uint256, bytes memory);
|
||||
----
|
||||
|
||||
There are multiple ways to make this work, including:
|
||||
@ -60,7 +60,7 @@ In this function, you return a number indicating whether you accept the call (0)
|
||||
|
||||
=== pre and postRelayedCall
|
||||
|
||||
After a relayed call is accepted, RelayHub will give your contract two opportunities to charge your user for their call, perform some bookeeping, etc.: _before_ and _after_ the actual relayed call is made. These functions are aptly named `preRelayedCall` and `postRelayedCall`.
|
||||
After a relayed call is accepted, RelayHub will give your contract two opportunities to charge your user for their call, perform some bookkeeping, etc.: _before_ and _after_ the actual relayed call is made. These functions are aptly named `preRelayedCall` and `postRelayedCall`.
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
@ -72,13 +72,12 @@ function preRelayedCall(bytes calldata context) external returns (bytes32);
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
|
||||
function postRelayedCall(
|
||||
bytes calldata context,
|
||||
bool success,
|
||||
uint actualCharge,
|
||||
bytes32 preRetVal
|
||||
) external;
|
||||
function postRelayedCall(
|
||||
bytes calldata context,
|
||||
bool success,
|
||||
uint256 actualCharge,
|
||||
bytes32 preRetVal
|
||||
) external;
|
||||
----
|
||||
|
||||
`postRelayedCall` will give you an accurate estimate of the transaction cost, making it a natural place to charge users. It will also let you know if the relayed call reverted or not. This allows you, for instance, to not charge users for reverted calls - but remember that you will be charged by the relayer nonetheless.
|
||||
@ -88,3 +87,4 @@ These functions allow you to implement, for instance, a flow where you charge yo
|
||||
== Further reading
|
||||
|
||||
Read our xref:gsn-strategies.adoc[guide on the payment strategies] pre-built and shipped in OpenZeppelin Contracts, or check out xref:api:GSN.adoc[the API reference of the GSN base contracts].
|
||||
|
||||
|
||||
@ -26,6 +26,8 @@ Once installed, you can use the contracts in the library by importing them:
|
||||
|
||||
[source,solidity]
|
||||
----
|
||||
// contracts/MyNFT.sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.6.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
|
||||
@ -46,14 +48,15 @@ To keep your system secure, you should **always** use the installed code as-is,
|
||||
The guides in the sidebar will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides:
|
||||
|
||||
* xref:access-control.adoc[Access Control]: decide who can perform each of the actions on your system.
|
||||
* xref:tokens.adoc[Tokens]: create tradeable assets or collectibles, like the well known xref:erc20.adoc[ERC20] and xref:erc721.adoc[ERC721] standards.
|
||||
* xref:tokens.adoc[Tokens]: create tradable assets or collectibles, like the well known xref:erc20.adoc[ERC20] and xref:erc721.adoc[ERC721] standards.
|
||||
* xref:gsn.adoc[Gas Station Network]: let your users interact with your contracts without having to pay for gas themselves.
|
||||
* xref:utilities.adoc[Utilities]: generic useful tools, including non-overflowing math, signature verification, and trustless paying systems.
|
||||
|
||||
The xref:api:token/ERC20.adoc[full API] is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts's development in the https://forum.openzeppelin.com[community forum].
|
||||
The xref:api:token/ERC20.adoc[full API] is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts' development in the https://forum.openzeppelin.com[community forum].
|
||||
|
||||
Finally, you may want to take a look at the https://blog.openzeppelin.com/guides/[guides on our blog], which cover several common use cases and good practices.. The following articles provide great background reading, though please note, some of the referenced tools have changed as the tooling in the ecosystem continues to rapidly evolve.
|
||||
|
||||
* https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05[The Hitchhiker’s Guide to Smart Contracts in Ethereum] will help you get an overview of the various tools available for smart contract development, and help you set up your environment.
|
||||
* https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094[A Gentle Introduction to Ethereum Programming, Part 1] provides very useful information on an introductory level, including many basic concepts from the Ethereum platform.
|
||||
* For a more in-depth dive, you may read the guide https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317[Designing the architecture for your Ethereum application], which discusses how to better structure your application and its relationship to the real world.
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
= New Releases and API Stability
|
||||
|
||||
Developing smart contracts is hard, and a conservative approach towards dependencies is sometimes favored. However, it is also very important to stay on top of new releases: these may include bugfixes, or deprecate old patterns in favor of newer and better practices.
|
||||
Developing smart contracts is hard, and a conservative approach towards dependencies is sometimes favored. However, it is also very important to stay on top of new releases: these may include bug fixes, or deprecate old patterns in favor of newer and better practices.
|
||||
|
||||
Here we describe when you should expect new releases to come out, and how this affects you as a user of OpenZeppelin Contracts.
|
||||
|
||||
@ -67,15 +67,16 @@ No events will be removed, and their arguments won't be changed in any way. New
|
||||
While attempts will generally be made to lower the gas costs of working with OpenZeppelin Contracts, there are no guarantees regarding this. In particular, users should not assume gas costs will not increase when upgrading library versions.
|
||||
|
||||
[[bugfixes]]
|
||||
=== Bugfixes
|
||||
=== Bug Fixes
|
||||
|
||||
The API stability guarantees may need to be broken in order to fix a bug, and we will do so. This decision won't be made lightly however, and all options will be explored to make the change as non-disruptive as possible. When sufficient, contracts or functions which may result in unsafe behaviour will be deprecated instead of removed (e.g. https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1543[#1543] and https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1550[#1550]).
|
||||
The API stability guarantees may need to be broken in order to fix a bug, and we will do so. This decision won't be made lightly however, and all options will be explored to make the change as non-disruptive as possible. When sufficient, contracts or functions which may result in unsafe behavior will be deprecated instead of removed (e.g. https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1543[#1543] and https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1550[#1550]).
|
||||
|
||||
[[solidity-compiler-version]]
|
||||
=== Solidity Compiler Version
|
||||
|
||||
Starting on version 0.5.0, the Solidity team switched to a faster release cycle, with minor releases every few weeks (v0.5.0 was released on November 2018, and v0.5.5 on March 2019), and major, breaking-change releases every couple months (with v0.6.0 scheduled for late March 2019). Including the compiler version in OpenZeppelin Contract's stability guarantees would therefore force the library to either stick to old compilers, or release frequent major updates simply to keep up with newer Solidity releases.
|
||||
Starting on version 0.5.0, the Solidity team switched to a faster release cycle, with minor releases every few weeks (v0.5.0 was released on November 2018, and v0.5.5 on March 2019), and major, breaking-change releases every couple of months (with v0.6.0 released on December 2019 and v0.7.0 on July 2020). Including the compiler version in OpenZeppelin Contract's stability guarantees would therefore force the library to either stick to old compilers, or release frequent major updates simply to keep up with newer Solidity releases.
|
||||
|
||||
Because of this, *the minimum required Solidity compiler version is not part of the stability guarantees*, and users may be required to upgrade their compiler when using newer versions of Contracts. Bugfixes will still be backported to older library releases so that all versions currently in use receive these updates.
|
||||
Because of this, *the minimum required Solidity compiler version is not part of the stability guarantees*, and users may be required to upgrade their compiler when using newer versions of Contracts. Bug fixes will still be backported to older library releases so that all versions currently in use receive these updates.
|
||||
|
||||
You can read more about the rationale behind this, the other options we considered and why we went down this path https://github.com/OpenZeppelin/openzeppelin-contracts/issues/1498#issuecomment-449191611[here].
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ Ah, the "token": blockchain's most powerful and most misunderstood tool.
|
||||
|
||||
A token is a _representation of something in the blockchain_. This something can be money, time, services, shares in a company, a virtual pet, anything. By representing things as tokens, we can allow smart contracts to interact with them, exchange them, create or destroy them.
|
||||
|
||||
[[but_first_coffee_a_primer_on_token_contracts]]
|
||||
== But First, [strikethrough]#Coffee# a Primer on Token Contracts
|
||||
|
||||
Much of the confusion surrounding tokens comes from two concepts getting mixed up: _token contracts_ and the actual _tokens_.
|
||||
@ -28,3 +29,4 @@ You've probably heard of the ERC20 or ERC721 token standards, and that's why you
|
||||
* xref:erc20.adoc[ERC20]: the most widespread token standard for fungible assets, albeit somewhat limited by its simplicity.
|
||||
* xref:erc721.adoc[ERC721]: the de-facto solution for non-fungible tokens, often used for collectibles and games.
|
||||
* xref:erc777.adoc[ERC777]: a richer standard for fungible tokens, enabling new use cases and building on past learnings. Backwards compatible with ERC20.
|
||||
* xref:erc1155.adoc[ERC1155]: a novel standard for multi-tokens, allowing for a single contract to represent multiple fungible and non-fungible tokens, along with batched operations for increased gas efficiency.
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
= Utilities
|
||||
|
||||
The OpenZeppelin Contracs provide a ton of useful utilities that you can use in your project. Here are some of the more popular ones.
|
||||
The OpenZeppelin Contracts provide a ton of useful utilities that you can use in your project. Here are some of the more popular ones.
|
||||
|
||||
[[cryptography]]
|
||||
== Cryptography
|
||||
|
||||
=== Checking Signatures On-Chain
|
||||
|
||||
xref:api:cryptography.adoc#ECDSA[`ECDSA`] provides functions for recovering and managing Ethereum account ECDSA signatures. These are often generated via https://web3js.readthedocs.io/en/v1.2.4/web3-eth.html#sign[`web3.eth.sign`], and are a 65 byte array (of type `bytes` in Solidity) arranged the follwing way: `[[v (1)], [r (32)], [s (32)]]`.
|
||||
xref:api:cryptography.adoc#ECDSA[`ECDSA`] provides functions for recovering and managing Ethereum account ECDSA signatures. These are often generated via https://web3js.readthedocs.io/en/v1.2.4/web3-eth.html#sign[`web3.eth.sign`], and are a 65 byte array (of type `bytes` in Solidity) arranged the following way: `[[v (1)], [r (32)], [s (32)]]`.
|
||||
|
||||
The data signer can be recovered with xref:api:cryptography.adoc#ECDSA-recover-bytes32-bytes-[`ECDSA.recover`], and its address compared to verify the signature. Most wallets will hash the data to sign and add the prefix '\x19Ethereum Signed Message:\n', so when attempting to recover the signer of an Ethereum signed message hash, you'll want to use xref:api:cryptography.adoc#ECDSA-toEthSignedMessageHash-bytes32-[`toEthSignedMessageHash`].
|
||||
|
||||
@ -90,7 +90,7 @@ If you want to Escrow some funds, check out xref:api:payment.adoc#Escrow[`Escrow
|
||||
[[collections]]
|
||||
== Collections
|
||||
|
||||
If you need support for more powerful collections than Solidity's native arrays and mappings, take a look at xref:api:utils.adoc#EnumerableSet[`EnumerableSet`] and xref:api:utils.adoc#EnumerableMap[`EnumerableMap`]. They are similar to mappings in that they store and remove elements in constant time and don't allow for repeated entries, but they also supports _enumeration_, which means you can easily query all stored entries both on and off-chain.
|
||||
If you need support for more powerful collections than Solidity's native arrays and mappings, take a look at xref:api:utils.adoc#EnumerableSet[`EnumerableSet`] and xref:api:utils.adoc#EnumerableMap[`EnumerableMap`]. They are similar to mappings in that they store and remove elements in constant time and don't allow for repeated entries, but they also support _enumeration_, which means you can easily query all stored entries both on and off-chain.
|
||||
|
||||
[[misc]]
|
||||
== Misc
|
||||
@ -98,3 +98,4 @@ If you need support for more powerful collections than Solidity's native arrays
|
||||
Want to check if an address is a contract? Use xref:api:utils.adoc#Address[`Address`] and xref:api:utils.adoc#Address-isContract-address-[`Address.isContract()`].
|
||||
|
||||
Want to keep track of some numbers that increment by 1 every time you want another one? Check out xref:api:utils.adoc#Counters[`Counters`]. This is useful for lots of things, like creating incremental identifiers, as shown on the xref:erc721.adoc[ERC721 guide].
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{{#links}}
|
||||
:{{slug target.fullName}}: pass:normal[xref:{{path}}#{{target.anchor}}[`{{target.fullName}}`]]
|
||||
:xref-{{slug target.fullName}}: xref:{{path}}#{{target.anchor}}
|
||||
:xref-{{slug target.anchor}}: xref:{{path}}#{{target.anchor}}
|
||||
{{/links}}
|
||||
|
||||
15
logo.svg
Normal file
15
logo.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<svg width="422" height="40" viewBox="0 0 422 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.7774 39.9836V29.6104H24.5468C21.4926 29.6104 18.6635 31.223 17.0993 33.8558L13.4584 39.9836H35.7774Z" fill="#63D2F9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.0332031 0.133484V10.5067H29.6139L35.7774 0.133484H0.0332031Z" fill="#4E5EE4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.1902 16.3452L0.0657959 39.9836H12.0995L28.9898 11.7036H22.3447C19.0023 11.7036 15.9058 13.4661 14.1902 16.3452Z" fill="#63B0F9"/>
|
||||
<path opacity="0.9" d="M288.7 30.0173C284.218 30.0173 281.078 26.6207 281.078 22.2251C281.078 17.8296 284.304 14.433 288.672 14.433C291.898 14.433 294.895 16.3739 295.695 19.6848H293.354C292.754 17.7439 290.87 16.488 288.729 16.488C285.56 16.488 283.419 18.9998 283.419 22.2251C283.419 25.5646 285.674 27.9622 288.786 27.9622C290.927 27.9622 292.84 26.7063 293.411 24.7654H295.723C294.952 28.0764 291.926 30.0173 288.7 30.0173ZM306.843 30.0173C302.39 30.0173 299.107 26.7349 299.107 22.2251C299.107 17.7439 302.447 14.433 306.872 14.433C311.354 14.433 314.608 17.7725 314.608 22.2251C314.608 26.6778 311.297 30.0173 306.843 30.0173ZM306.843 27.9622C310.041 27.9622 312.296 25.5361 312.296 22.2251C312.296 18.9427 310.041 16.488 306.843 16.488C303.646 16.488 301.419 18.9713 301.419 22.2251C301.419 25.5646 303.674 27.9622 306.843 27.9622ZM319.134 29.6462V14.804H321.389V16.9733H321.56C322.188 15.6318 323.787 14.433 326.099 14.433C329.554 14.433 331.638 17.0304 331.638 20.3128V29.6462H329.382V20.4555C329.382 18.0864 327.641 16.5451 325.557 16.5451C323.216 16.5451 321.389 18.3433 321.389 20.798V29.6462H319.134ZM342.815 29.6462C340.074 29.6462 338.39 28.162 338.39 25.165V16.7164H335.592V14.804H337.819C338.219 14.804 338.533 14.5471 338.533 14.0619V10.4941H340.645V14.804H345.213V16.7164H340.645V25.1365C340.645 26.7349 341.245 27.6768 342.957 27.6768H345.013V29.6462H342.815ZM349.738 29.6462V14.804H351.965V17.5727H352.136C352.564 16.3168 354.02 14.804 356.19 14.804H357.446V17.0589H356.219C353.507 17.0589 351.993 19.1711 351.993 21.9968V29.6462H349.738ZM367.367 30.0173C362.999 30.0173 359.973 26.792 359.973 22.2537C359.973 17.6868 362.999 14.433 367.196 14.433C370.308 14.433 371.963 16.431 372.42 17.2016H372.591V14.804H374.847V29.6462H372.677V27.3057H372.506C372.135 27.8481 370.593 30.0173 367.367 30.0173ZM367.51 27.9908C370.736 27.9908 372.677 25.3648 372.677 22.2537C372.677 18.6002 370.393 16.488 367.453 16.488C364.398 16.488 362.286 18.8856 362.286 22.2537C362.286 25.7359 364.398 27.9908 367.51 27.9908ZM386.709 30.0173C382.227 30.0173 379.087 26.6207 379.087 22.2251C379.087 17.8296 382.312 14.433 386.68 14.433C389.906 14.433 392.904 16.3739 393.703 19.6848H391.362C390.763 17.7439 388.879 16.488 386.737 16.488C383.569 16.488 381.427 18.9998 381.427 22.2251C381.427 25.5646 383.683 27.9622 386.795 27.9622C388.936 27.9622 390.848 26.7063 391.419 24.7654H393.732C392.961 28.0764 389.935 30.0173 386.709 30.0173ZM404.052 29.6462C401.312 29.6462 399.627 28.162 399.627 25.165V16.7164H396.83V14.804H399.056C399.456 14.804 399.77 14.5471 399.77 14.0619V10.4941H401.883V14.804H406.45V16.7164H401.883V25.1365C401.883 26.7349 402.482 27.6768 404.195 27.6768H406.25V29.6462H404.052ZM415.886 30.0173C412.375 30.0173 410.376 28.1049 410.119 25.3363H412.317C412.574 27.1059 413.831 28.0479 416 28.0479C418.227 28.0479 419.454 26.9632 419.454 25.4505C419.454 21.2832 410.576 24.4515 410.576 18.5717C410.576 16.0599 412.831 14.433 415.943 14.433C418.684 14.433 420.968 16.0314 421.196 18.7144H419.026C418.826 17.3158 417.77 16.3739 415.8 16.3739C413.945 16.3739 412.746 17.2872 412.746 18.5717C412.746 22.3393 421.653 19.1996 421.653 25.3363C421.653 28.1335 419.34 30.0173 415.886 30.0173Z" fill="#282846"/>
|
||||
<path d="M61.3795 30.03C55.3284 30.03 50.8757 25.6059 50.8757 19.669C50.8757 13.7892 55.3569 9.30797 61.408 9.30797C67.4591 9.30797 71.9403 13.8463 71.9403 19.669C71.9403 25.5488 67.4305 30.03 61.3795 30.03ZM61.408 26.4051C65.2327 26.4051 67.9728 23.5508 67.9728 19.669C67.9728 15.8443 65.2327 12.9329 61.408 12.9329C57.5547 12.9329 54.8146 15.8443 54.8146 19.669C54.8146 23.5508 57.5547 26.4051 61.408 26.4051ZM75.9923 36.2238V14.6455H79.6457V16.5578H79.8455C80.2451 15.9299 81.6152 14.2744 84.3553 14.2744C88.5511 14.2744 91.4339 17.4141 91.4339 22.0951C91.4339 26.7761 88.5796 30.03 84.4695 30.03C81.815 30.03 80.3879 28.5458 79.9026 27.718H79.7028V36.2238H75.9923ZM83.6417 26.6619C86.0393 26.6619 87.6662 24.8067 87.6662 22.1522C87.6662 19.4121 86.0393 17.6424 83.6132 17.6424C81.1585 17.6424 79.6172 19.6119 79.6172 22.1522C79.6172 24.9494 81.3298 26.6619 83.6417 26.6619ZM102.051 30.03C97.6266 30.03 94.4869 26.719 94.4869 22.2378C94.4869 17.4997 97.6551 14.2744 102.051 14.2744C106.874 14.2744 109.5 17.8422 109.5 22.0666V23.2368H98.0833C98.1975 25.5202 99.7673 27.0615 102.165 27.0615C103.992 27.0615 105.39 26.2053 105.904 24.9779H109.358C108.616 28.032 105.933 30.03 102.051 30.03ZM98.1404 20.6109H105.961C105.79 18.5844 104.22 17.2428 102.051 17.2428C99.9671 17.2428 98.3687 18.7271 98.1404 20.6109ZM113.495 29.6589V14.6455H117.035V16.4722H117.234C117.834 15.359 119.318 14.2744 121.459 14.2744C124.827 14.2744 126.882 16.6434 126.882 19.8402V29.6589H123.171V20.8107C123.171 18.984 122.001 17.7566 120.288 17.7566C118.49 17.7566 117.206 19.1837 117.206 21.0676V29.6589H113.495ZM130.563 29.6589V26.2623L140.952 13.1612V12.9614H130.934V9.67903H145.69V13.0471L135.301 26.1482V26.3765H145.748V29.6589H130.563ZM155.794 30.03C151.369 30.03 148.23 26.719 148.23 22.2378C148.23 17.4997 151.398 14.2744 155.794 14.2744C160.617 14.2744 163.243 17.8422 163.243 22.0666V23.2368H151.826C151.94 25.5202 153.51 27.0615 155.908 27.0615C157.734 27.0615 159.133 26.2053 159.647 24.9779H163.1C162.358 28.032 159.675 30.03 155.794 30.03ZM151.883 20.6109H159.704C159.533 18.5844 157.963 17.2428 155.794 17.2428C153.71 17.2428 152.112 18.7271 151.883 20.6109ZM167.238 36.2238V14.6455H170.892V16.5578H171.091C171.491 15.9299 172.861 14.2744 175.601 14.2744C179.797 14.2744 182.68 17.4141 182.68 22.0951C182.68 26.7761 179.825 30.03 175.715 30.03C173.061 30.03 171.634 28.5458 171.148 27.718H170.949V36.2238H167.238ZM174.888 26.6619C177.285 26.6619 178.912 24.8067 178.912 22.1522C178.912 19.4121 177.285 17.6424 174.859 17.6424C172.404 17.6424 170.863 19.6119 170.863 22.1522C170.863 24.9494 172.576 26.6619 174.888 26.6619ZM186.675 36.2238V14.6455H190.328V16.5578H190.528C190.927 15.9299 192.298 14.2744 195.038 14.2744C199.233 14.2744 202.116 17.4141 202.116 22.0951C202.116 26.7761 199.262 30.03 195.152 30.03C192.497 30.03 191.07 28.5458 190.585 27.718H190.385V36.2238H186.675ZM194.324 26.6619C196.722 26.6619 198.349 24.8067 198.349 22.1522C198.349 19.4121 196.722 17.6424 194.296 17.6424C191.841 17.6424 190.3 19.6119 190.3 22.1522C190.3 24.9494 192.012 26.6619 194.324 26.6619ZM212.733 30.03C208.309 30.03 205.169 26.719 205.169 22.2378C205.169 17.4997 208.337 14.2744 212.733 14.2744C217.557 14.2744 220.183 17.8422 220.183 22.0666V23.2368H208.766C208.88 25.5202 210.45 27.0615 212.847 27.0615C214.674 27.0615 216.073 26.2053 216.586 24.9779H220.04C219.298 28.032 216.615 30.03 212.733 30.03ZM208.823 20.6109H216.643C216.472 18.5844 214.902 17.2428 212.733 17.2428C210.649 17.2428 209.051 18.7271 208.823 20.6109ZM227.831 29.6589C225.205 29.6589 223.721 28.0891 223.721 25.4346V8.25189H227.432V25.0921C227.432 25.9484 227.86 26.4051 228.63 26.4051H229.23V29.6589H227.831ZM234.652 12.6475C233.31 12.6475 232.368 11.8197 232.368 10.4782C232.368 9.1938 233.31 8.33752 234.652 8.33752C235.993 8.33752 236.935 9.1938 236.935 10.4782C236.935 11.8197 235.993 12.6475 234.652 12.6475ZM232.797 29.6589V14.6455H236.507V29.6589H232.797ZM241.016 29.6589V14.6455H244.555V16.4722H244.755C245.354 15.359 246.838 14.2744 248.979 14.2744C252.347 14.2744 254.402 16.6434 254.402 19.8402V29.6589H250.692V20.8107C250.692 18.984 249.521 17.7566 247.809 17.7566C246.011 17.7566 244.726 19.1837 244.726 21.0676V29.6589H241.016Z" fill="#282846"/>
|
||||
<path opacity="0.9" d="M269.325 30.2504H267.125V9.62091H269.325V30.2504Z" fill="#282846"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="421.8" height="40" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.1 KiB |
2245
package-lock.json
generated
2245
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openzeppelin-solidity",
|
||||
"version": "3.0.2",
|
||||
"version": "3.2.0",
|
||||
"description": "Secure Smart Contract library for Solidity",
|
||||
"files": [
|
||||
"/contracts/**/*.sol",
|
||||
@ -20,7 +20,9 @@
|
||||
"lint:js": "eslint --ignore-path .gitignore .",
|
||||
"lint:js:fix": "eslint --ignore-path .gitignore . --fix",
|
||||
"lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"",
|
||||
"prepare": "node scripts/prepare.js",
|
||||
"prepublish": "rimraf build contracts/build",
|
||||
"prepare": "npm run compile",
|
||||
"prepack": "node scripts/remove-ignored-artifacts.js",
|
||||
"release": "scripts/release/release.sh",
|
||||
"version": "scripts/release/version.sh",
|
||||
"test": "mocha --exit --recursive"
|
||||
@ -49,7 +51,7 @@
|
||||
"@openzeppelin/gsn-helpers": "^0.2.3",
|
||||
"@openzeppelin/gsn-provider": "^0.1.10",
|
||||
"@openzeppelin/test-environment": "^0.1.4",
|
||||
"@openzeppelin/test-helpers": "^0.5.5",
|
||||
"@openzeppelin/test-helpers": "^0.5.6",
|
||||
"chai": "^4.2.0",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
@ -58,15 +60,16 @@
|
||||
"eslint-plugin-node": "^10.0.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"ethereumjs-util": "^6.2.0",
|
||||
"ethereumjs-util": "^7.0.1",
|
||||
"ganache-core-coverage": "https://github.com/OpenZeppelin/ganache-core-coverage/releases/download/2.5.3-coverage/ganache-core-coverage-2.5.3.tgz",
|
||||
"lodash.startcase": "^4.4.0",
|
||||
"lodash.zip": "^4.2.0",
|
||||
"micromatch": "^4.0.2",
|
||||
"mocha": "^7.1.2",
|
||||
"solhint": "^3.0.0-rc.8",
|
||||
"mocha": "^8.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"solhint": "^3.0.0",
|
||||
"solidity-coverage": "github:rotcivegaf/solidity-coverage#5875f5b7bc74d447f3312c9c0e9fc7814b482477",
|
||||
"solidity-docgen": "^0.4.1"
|
||||
"solidity-docgen": "^0.5.3"
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
14
renovate.json
Normal file
14
renovate.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"rangeStrategy": "update-lockfile",
|
||||
"extends": [
|
||||
"config:base",
|
||||
"group:allNonMajor",
|
||||
"schedule:weekly"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"extends": ["packages:eslint"],
|
||||
"enabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -24,7 +24,7 @@ const links = files.map((file) => {
|
||||
|
||||
// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20')
|
||||
const sortedLinks = links.sort(function (a, b) {
|
||||
return a.title.toLowerCase().localeCompare(b.title.toLowerCase());
|
||||
return a.title.toLowerCase().localeCompare(b.title.toLowerCase(), undefined, { numeric: true });
|
||||
});
|
||||
|
||||
for (const link of sortedLinks) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user