Compare commits

...

75 Commits

Author SHA1 Message Date
a673994de5 4.0.0 2021-03-23 12:06:54 -03:00
9b0e27c98c add missing rewrite rule in scripts/migrate-imports.js
(cherry picked from commit a3712a3288)
2021-03-22 18:08:36 +01:00
90a72f9acd Fix ERC721URIStorage in documentation
(cherry picked from commit 7c1625b0e0)
2021-03-15 16:48:43 -03:00
1ee939e7c4 4.0.0-rc.0 2021-03-09 15:38:49 +01:00
59f33c1cc1 remove extra changelog entry 2021-03-09 15:32:54 +01:00
d104ced953 fix changelog format
(cherry picked from commit 2658e01baa)
2021-03-09 15:25:22 +01:00
1fd54698ff Update lockfile (#2573)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
(cherry picked from commit 9612b891c9)
2021-03-09 15:23:05 +01:00
27fc833550 Make ERC1155.uri public (#2576)
(cherry picked from commit 5dbbda5435)
2021-03-08 17:37:25 -03:00
0b3e0d74b0 Further reorganisation of the repo (#2575)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
(cherry picked from commit f076ff5dbd)
2021-03-08 17:37:03 -03:00
d75b4cf613 Update changelog to list beta bugfix separately
(cherry picked from commit 5aab6ff81b)
2021-03-08 17:37:00 -03:00
b1e0aa487d Fix AccessControlEnumerable not tracking renounceRole (#2572)
* Fix AccessControlEnumerable not tracking renounceRole

* Updated changelog

(cherry picked from commit 7adf0d88a0)
2021-03-08 14:32:21 +01:00
6505e28c40 removes invalid character in comments (#2571)
(cherry picked from commit fc004c0ad2)
2021-03-08 14:32:09 +01:00
f07c39be8a Add ERC165 interface detection to AccessControl (#2562)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
(cherry picked from commit 29ffe6f426)
2021-03-04 18:50:49 -03:00
69ca2ad676 Fix name of ERC721URIStorage contract in changelog
(cherry picked from commit 3d587f3043)
2021-03-03 12:50:05 -03:00
ae1e384a9a Fix prepack script
(cherry picked from commit 10c52439dd5118d4b671e12d691bfde42c987fb9)
2021-03-03 16:32:22 +01:00
954f6110d6 4.0.0-beta.1 2021-03-03 16:23:38 +01:00
4390b8df12 Add ERC721URIStorage extension (#2555)
(cherry picked from commit 1705067e65)
2021-03-03 16:15:51 +01:00
cb88e15b33 Enable optimizations when publishing package (#2557)
(cherry picked from commit 618a735816)
2021-03-03 16:15:26 +01:00
136de91049 Rename variable master to implementation #2 (#2553)
(cherry picked from commit 103ff8e23d)
2021-03-03 12:33:03 +01:00
e2bf45f262 Rename variable master to implementation
(cherry picked from commit cdb929aada)
2021-03-02 21:30:26 -03:00
93d990c653 Optimize constructor of ERC777 (#2551)
(cherry picked from commit 62af16b9f2)
2021-03-02 21:31:07 +01:00
3dfd02b4b4 Fix link to TimelockController
(cherry picked from commit ba1d773176)
2021-03-02 21:14:33 +01:00
7a7bd8f6d7 Fix typo Controler -> Controller
(cherry picked from commit 583146f9d6)
2021-03-02 21:14:26 +01:00
16312fcfb9 Rename UpgradeableProxy to ERC1967Proxy (#2547)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
(cherry picked from commit c789941d76)
2021-03-02 21:14:08 +01:00
a81a88cca0 Fix mentions of buidler (#2548)
(cherry picked from commit 232c355b3a)
2021-03-02 21:14:00 +01:00
5acedf5027 Change title of meta transactions page in docs sidebar
(cherry picked from commit 773c7265e8)
2021-03-02 21:13:51 +01:00
566c601d41 Update lockfile (#2546)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
(cherry picked from commit 742c436d28)
2021-03-02 21:13:39 +01:00
15214a53ce Optimize implementation of ERC20Capped (#2524)
(cherry picked from commit 36b855972b)
2021-03-01 12:09:21 -03:00
d5f4862405 Fix package.json files field
(cherry picked from commit 735c03fcf3)
2021-02-24 00:36:08 -03:00
4a1985f870 Fix migrate-imports.js test for upgradeable paths
(cherry picked from commit 4519c237c5)
2021-02-24 00:20:07 -03:00
ac8279a0a5 Update Antora component version 2021-02-23 23:31:48 -03:00
7cab19a2e4 Check upgradeable paths in migrate-imports test
(cherry picked from commit 4ee9fd77fd)
2021-02-23 23:31:34 -03:00
556cdf5f1a 4.0.0-beta.0 2021-02-22 17:44:21 -03:00
c760fe9a2e Update package-lock.json 2021-02-22 17:44:02 -03:00
24a0bc23cf Reorganize the repo structure (#2503)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-22 16:44:16 +00:00
c3178ff942 Add message to caution that SafeMath.sol is for Solidity 0.8 2021-02-19 18:17:42 -03:00
f8cc8b844a Minimal support for ERC2771 (GSNv2) (#2508)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-19 15:36:48 -03:00
e341bdc1b7 Remove enumerable from AccessControl and add AccessControlEnumerable extension (#2512)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-19 17:36:56 +00:00
09734e8028 Remove enumerable from ERC721 and add an ERC721Enumerable extension (#2511)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-19 13:24:39 -03:00
7d20d0e2d2 Use immutable variables where possible (#2528)
Co-authored-by: rotciv <victorfage@gmail.com>
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
2021-02-19 11:11:54 -03:00
0059b17dfc Remove _isConstructor() check in initializer modifier (#2531)
* Remove _isConstructor() check in initializer modifier

* add changelog entry
2021-02-18 20:53:00 -03:00
e733b24dfe Refactor ERC165 to use function overriding instead of storage (#2505)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-18 19:02:28 +00:00
f7c8252611 Remove GSNv1 contracts (#2521)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-18 15:27:18 +00:00
e66e3ca523 Improve gas efficiency of EnumerableMap (#2518)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-18 15:19:57 +00:00
24660c3e48 Fix keccak256 typo (#2525) 2021-02-17 13:34:39 +01:00
ee6348a7a0 change CHANGELOG indentation for consistency 2021-02-09 17:25:41 +01:00
a44303c373 Remove double sload when doing math checks in tokens (#2506)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-09 12:58:23 -03:00
f49e9ee41b Update lockfile (#2493)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-09 11:59:35 -03:00
1ba03b164a Add support for eth-gas-reporter (#2501)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-09 00:42:35 +00:00
9c1e703990 Add a Strings.toHexString function (#2504)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-08 20:55:56 +00:00
f2112be4d8 Add revert string to Counter decrement overflow (#2500) 2021-02-04 20:28:13 +00:00
c82895fb65 Fix codecov reports 2021-02-04 17:15:32 -03:00
b840341a77 Remove the storage associated with decimals (#2502)
* Removing the storage associated with decimals

* changelog entry

* changelog link to new issue number

* Update contracts/token/ERC20/ERC20.sol

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>

* Update contracts/token/ERC20/ERC20.sol

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>

* Update CHANGELOG.md

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-02-04 20:06:00 +01:00
ed7623273a Fix prepare-docs-solc.js for Hardhat 2021-02-04 14:22:19 -03:00
9425a7e0ab Merge branch 'solc-0.8'
Conflicts:
	CHANGELOG.md
	package-lock.json
	test/math/SafeMath.test.js
2021-02-02 22:13:28 +01:00
93438eca0b Merge 3.4 master into solc-0.8 (#2499)
* 3.4.0-rc.0

* Allow manual dispatch of Test CI job

* Update lockfile (#2481)

Co-authored-by: Renovate Bot <bot@renovateapp.com>

* Add "available since" comments in documentation

* Add "available since" comments in documentation

(cherry picked from commit 63a0343dda)

* Remove SafeMathMock compilation warnings (#2497)

* Remove SafeMathMock compilation warnings (#2497)

(cherry picked from commit f4e57fd529)

* 3.4.0

* fix safemath test to use renamed function from the mock

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-02 22:07:56 +01:00
e28615628b Merge branch 'release-v3.4' 2021-02-02 16:16:16 -03:00
fa64a1ced0 3.4.0 2021-02-02 16:15:12 -03:00
0f553e7f9e Remove SafeMathMock compilation warnings (#2497)
(cherry picked from commit f4e57fd529)
2021-02-02 12:03:02 -03:00
f4e57fd529 Remove SafeMathMock compilation warnings (#2497) 2021-02-02 11:46:23 -03:00
a0e2bca79a Add "available since" comments in documentation
(cherry picked from commit 63a0343dda)
2021-02-01 21:45:27 -03:00
63a0343dda Add "available since" comments in documentation 2021-02-01 21:44:58 -03:00
5db7413827 re-enabling safemath revert reasons in ERC20, ERC777 and ERC1155 (#2491)
* re-enabling safemath revert reasons in ERC20 and ERC1155

* adding revert messages to ERC777

* removing uncheck block
2021-02-01 11:00:16 +01:00
d163aeb80d Update lockfile (#2481)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-29 19:41:00 -03:00
60205944bb Adopt new Solidity features interfaceId, try/catch, keccak constants (#2487)
* Clean code

-  using type().interfaceId to improve readeability of ERC165 registration
- hardcoding some keccak256 that are otherwise computed at construction.

* hardcode keccak256 result

* Improve code readeability using try/catch

* Remove hardcoded hash 

tests show that solc 0.8.0 does the optimization as expected

* Use try/catch to improve readability

* ERC165Checker: Do not revert when returndata is empty + new test

* Address PR comments

* improve testing of ERC721Receiver errors

* put back comment about invalid interface id

* coverage does not support 0.8.1. Reverting back to 0.8.0

* bubble all data with length > 0 if onERC721Receive fails.

* Fix test: revert without message trigger is bubble with the default message

* using enum object to improve readability
2021-01-29 22:20:49 +01:00
03832c130c Make Context._msgData return "bytes calldata" (#2492) 2021-01-29 12:51:51 -03:00
9f93e25b88 Merge branch 'solc-0.7' into 'solc-0.8' 2021-01-27 18:36:46 -03:00
afaebc3869 Disable solhint until Solidity 0.8 supported 2021-01-27 18:17:13 -03:00
fdf57a9788 Lint 2021-01-27 18:14:15 -03:00
5609cd4c74 Fix merge errors 2021-01-27 18:04:52 -03:00
a0323d446c Transition from buidler to hardhat 2021-01-27 11:37:18 +01:00
0db76e98f9 Merge branch 'solc-0.7' into solc-0.8 2021-01-27 11:28:23 +01:00
bcc7192af7 Allow manual dispatch of Test CI job 2021-01-26 18:20:33 -03:00
ff300b10e1 3.4.0-rc.0 2021-01-26 13:31:55 -03:00
974c534210 Update contracts to support Solidity 0.8.x (#2442)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
2021-01-14 19:38:53 -03:00
274 changed files with 28706 additions and 8318 deletions

View File

@ -26,11 +26,18 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true'
- run: npm run lint
- run: npm run test
env:
FORCE_COLOR: 1
ENABLE_GAS_REPORT: 1
- name: Print gas report
run: cat gas-report.txt
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- uses: actions/setup-node@v2
with:
node-version: 10.x
@ -43,4 +50,6 @@ jobs:
- run: npm ci
if: steps.cache.outputs.cache-hit != 'true'
- run: npm run coverage
env:
NODE_OPTIONS: --max_old_space_size=4096
- uses: codecov/codecov-action@v1

2
.gitignore vendored
View File

@ -54,6 +54,6 @@ allFiredEvents
.coverage_cache
.coverage_contracts
# buidler
# hardhat
cache
artifacts

View File

@ -1,6 +1,45 @@
# Changelog
## Unreleased
## 4.0.0 (2021-03-23)
* Now targeting the 0.8.x line of Solidity compilers. For 0.6.x (resp 0.7.x) support, use version 3.4.0 (resp 3.4.0-solc-0.7) of OpenZeppelin.
* `Context`: making `_msgData` return `bytes calldata` instead of `bytes memory` ([#2492](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2492))
* `ERC20`: removed the `_setDecimals` function and the storage slot associated to decimals. ([#2502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2502))
* `Strings`: addition of a `toHexString` function. ([#2504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2504))
* `EnumerableMap`: change implementation to optimize for `key → value` lookups instead of enumeration. ([#2518](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2518))
* `GSN`: deprecate GSNv1 support in favor of upcoming support for GSNv2. ([#2521](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2521))
* `ERC165`: remove uses of storage in the base ERC165 implementation. ERC165 based contracts now use storage-less virtual functions. Old behavior remains available in the `ERC165Storage` extension. ([#2505](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2505))
* `Initializable`: make initializer check stricter during construction. ([#2531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2531))
* `ERC721`: remove enumerability of tokens from the base implementation. This feature is now provided separately through the `ERC721Enumerable` extension. ([#2511](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2511))
* `AccessControl`: removed enumerability by default for a more lightweight contract. It is now opt-in through `AccessControlEnumerable`. ([#2512](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2512))
* Meta Transactions: add `ERC2771Context` and a `MinimalForwarder` for meta-transactions. ([#2508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2508))
* Overall reorganization of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503))
* `ERC20Capped`: optimize gas usage by enforcing the check directly in `_mint`. ([#2524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2524))
* Rename `UpgradeableProxy` to `ERC1967Proxy`. ([#2547](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2547))
* `ERC777`: optimize the gas costs of the constructor. ([#2551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2551))
* `ERC721URIStorage`: add a new extension that implements the `_setTokenURI` behavior as it was available in 3.4.0. ([#2555](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2555))
* `AccessControl`: added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562))
* `ERC1155`: make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576))
### Bug fixes for beta releases
* `AccessControlEnumerable`: Fixed `renounceRole` not updating enumerable set of addresses for a role. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572))
### How to upgrade from 3.x
Since this version has moved a few contracts to different directories, users upgrading from a previous version will need to adjust their import statements. To make this easier, the package includes a script that will migrate import statements automatically. After upgrading to the latest version of the package, run:
```
npx openzeppelin-contracts-migrate-imports
```
Make sure you're using git or another version control system to be able to recover from any potential error in our script.
### How to upgrade from 4.0-beta.x
Some further changes have been done between the different beta iterations. Transitions made during this period are configured in the `migrate-imports` script. Consequently, you can upgrade from any previous 4.0-beta.x version using the same script as described in the *How to upgrade from 3.x* section.
## 3.4.0 (2021-02-02)
* `BeaconProxy`: added new kind of proxy that allows simultaneous atomic upgrades. ([#2411](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2411))
* `EIP712`: added helpers to verify EIP712 typed data signatures on chain. ([#2418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2418))

View File

@ -27,7 +27,7 @@ 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.7.0;
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

View File

@ -1,20 +0,0 @@
const fs = require('fs');
const path = require('path');
usePlugin('solidity-coverage');
usePlugin('@nomiclabs/buidler-truffle5');
for (const f of fs.readdirSync(path.join(__dirname, 'buidler'))) {
require(path.join(__dirname, 'buidler', f));
}
module.exports = {
networks: {
buidlerevm: {
blockGasLimit: 10000000,
},
},
solc: {
version: '0.7.4',
},
};

View File

@ -1,5 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";

View File

@ -1,230 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
import "./IRelayRecipient.sol";
import "./IRelayHub.sol";
/**
* @dev Base GSN recipient contract: includes the {IRelayRecipient} interface
* and enables GSN support on all contracts in the inheritance tree.
*
* TIP: This contract is abstract. The functions {IRelayRecipient-acceptRelayedCall},
* {_preRelayedCall}, and {_postRelayedCall} are not implemented and must be
* provided by derived contracts. See the
* xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategies] for more
* information on how to use the pre-built {GSNRecipientSignature} and
* {GSNRecipientERC20Fee}, or how to write your own.
*/
abstract contract GSNRecipient is IRelayRecipient, Context {
// Default RelayHub address, deployed on mainnet and all testnets at the same address
address private _relayHub = 0xD216153c06E857cD7f72665E0aF1d7D82172F494;
uint256 constant private _RELAYED_CALL_ACCEPTED = 0;
uint256 constant private _RELAYED_CALL_REJECTED = 11;
// How much gas is forwarded to postRelayedCall
uint256 constant internal _POST_RELAYED_CALL_MAX_GAS = 100000;
/**
* @dev Emitted when a contract changes its {IRelayHub} contract to a new one.
*/
event RelayHubChanged(address indexed oldRelayHub, address indexed newRelayHub);
/**
* @dev Returns the address of the {IRelayHub} contract for this recipient.
*/
function getHubAddr() public view virtual override returns (address) {
return _relayHub;
}
/**
* @dev Switches to a new {IRelayHub} instance. This method is added for future-proofing: there's no reason to not
* use the default instance.
*
* IMPORTANT: After upgrading, the {GSNRecipient} will no longer be able to receive relayed calls from the old
* {IRelayHub} instance. Additionally, all funds should be previously withdrawn via {_withdrawDeposits}.
*/
function _upgradeRelayHub(address newRelayHub) internal virtual {
address currentRelayHub = _relayHub;
require(newRelayHub != address(0), "GSNRecipient: new RelayHub is the zero address");
require(newRelayHub != currentRelayHub, "GSNRecipient: new RelayHub is the current one");
emit RelayHubChanged(currentRelayHub, newRelayHub);
_relayHub = newRelayHub;
}
/**
* @dev Returns the version string of the {IRelayHub} for which this recipient implementation was built. If
* {_upgradeRelayHub} is used, the new {IRelayHub} instance should be compatible with this version.
*/
// This function is view for future-proofing, it may require reading from
// storage in the future.
function relayHubVersion() public view virtual returns (string memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return "1.0.0";
}
/**
* @dev Withdraws the recipient's deposits in `RelayHub`.
*
* Derived contracts should expose this in an external interface with proper access control.
*/
function _withdrawDeposits(uint256 amount, address payable payee) internal virtual {
IRelayHub(getHubAddr()).withdraw(amount, payee);
}
// Overrides for Context's functions: when called from RelayHub, sender and
// data require some pre-processing: the actual sender is stored at the end
// of the call data, which in turns means it needs to be removed from it
// when handling said data.
/**
* @dev Replacement for msg.sender. Returns the actual sender of a transaction: msg.sender for regular transactions,
* and the end-user for GSN relayed calls (where msg.sender is actually `RelayHub`).
*
* IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead.
*/
function _msgSender() internal view virtual override returns (address payable) {
if (msg.sender != getHubAddr()) {
return msg.sender;
} else {
return _getRelayedCallSender();
}
}
/**
* @dev Replacement for msg.data. Returns the actual calldata of a transaction: msg.data for regular transactions,
* and a reduced version for GSN relayed calls (where msg.data contains additional information).
*
* IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.data`, and use {_msgData} instead.
*/
function _msgData() internal view virtual override returns (bytes memory) {
if (msg.sender != getHubAddr()) {
return msg.data;
} else {
return _getRelayedCallData();
}
}
// Base implementations for pre and post relayedCall: only RelayHub can invoke them, and data is forwarded to the
// internal hook.
/**
* @dev See `IRelayRecipient.preRelayedCall`.
*
* This function should not be overridden directly, use `_preRelayedCall` instead.
*
* * Requirements:
*
* - the caller must be the `RelayHub` contract.
*/
function preRelayedCall(bytes memory context) public virtual override returns (bytes32) {
require(msg.sender == getHubAddr(), "GSNRecipient: caller is not RelayHub");
return _preRelayedCall(context);
}
/**
* @dev See `IRelayRecipient.preRelayedCall`.
*
* Called by `GSNRecipient.preRelayedCall`, which asserts the caller is the `RelayHub` contract. Derived contracts
* must implement this function with any relayed-call preprocessing they may wish to do.
*
*/
function _preRelayedCall(bytes memory context) internal virtual returns (bytes32);
/**
* @dev See `IRelayRecipient.postRelayedCall`.
*
* This function should not be overridden directly, use `_postRelayedCall` instead.
*
* * Requirements:
*
* - the caller must be the `RelayHub` contract.
*/
function postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) public virtual override {
require(msg.sender == getHubAddr(), "GSNRecipient: caller is not RelayHub");
_postRelayedCall(context, success, actualCharge, preRetVal);
}
/**
* @dev See `IRelayRecipient.postRelayedCall`.
*
* Called by `GSNRecipient.postRelayedCall`, which asserts the caller is the `RelayHub` contract. Derived contracts
* must implement this function with any relayed-call postprocessing they may wish to do.
*
*/
function _postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) internal virtual;
/**
* @dev Return this in acceptRelayedCall to proceed with the execution of a relayed call. Note that this contract
* will be charged a fee by RelayHub
*/
function _approveRelayedCall() internal pure virtual returns (uint256, bytes memory) {
return _approveRelayedCall("");
}
/**
* @dev See `GSNRecipient._approveRelayedCall`.
*
* This overload forwards `context` to _preRelayedCall and _postRelayedCall.
*/
function _approveRelayedCall(bytes memory context) internal pure virtual returns (uint256, bytes memory) {
return (_RELAYED_CALL_ACCEPTED, context);
}
/**
* @dev Return this in acceptRelayedCall to impede execution of a relayed call. No fees will be charged.
*/
function _rejectRelayedCall(uint256 errorCode) internal pure virtual returns (uint256, bytes memory) {
return (_RELAYED_CALL_REJECTED + errorCode, "");
}
/*
* @dev Calculates how much RelayHub will charge a recipient for using `gas` at a `gasPrice`, given a relayer's
* `serviceFee`.
*/
function _computeCharge(uint256 gas, uint256 gasPrice, uint256 serviceFee) internal pure virtual returns (uint256) {
// The fee is expressed as a percentage. E.g. a value of 40 stands for a 40% fee, so the recipient will be
// charged for 1.4 times the spent amount.
return (gas * gasPrice * (100 + serviceFee)) / 100;
}
function _getRelayedCallSender() private pure returns (address payable result) {
// We need to read 20 bytes (an address) located at array index msg.data.length - 20. In memory, the array
// is prefixed with a 32-byte length value, so we first add 32 to get the memory read index. However, doing
// so would leave the address in the upper 20 bytes of the 32-byte word, which is inconvenient and would
// require bit shifting. We therefore subtract 12 from the read index so the address lands on the lower 20
// bytes. This can always be done due to the 32-byte prefix.
// The final memory read index is msg.data.length - 20 + 32 - 12 = msg.data.length. Using inline assembly is the
// easiest/most-efficient way to perform this operation.
// These fields are not accessible from assembly
bytes memory array = msg.data;
uint256 index = msg.data.length;
// solhint-disable-next-line no-inline-assembly
assembly {
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
result := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
}
return result;
}
function _getRelayedCallData() private pure returns (bytes memory) {
// RelayHub appends the sender address at the end of the calldata, so in order to retrieve the actual msg.data,
// we must strip the last 20 bytes (length of an address type) from it.
uint256 actualDataLength = msg.data.length - 20;
bytes memory actualData = new bytes(actualDataLength);
for (uint256 i = 0; i < actualDataLength; ++i) {
actualData[i] = msg.data[i];
}
return actualData;
}
}

View File

@ -1,154 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./GSNRecipient.sol";
import "../math/SafeMath.sol";
import "../access/Ownable.sol";
import "../token/ERC20/SafeERC20.sol";
import "../token/ERC20/ERC20.sol";
/**
* @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that charges transaction fees in a special purpose ERC20
* token, which we refer to as the gas payment token. The amount charged is exactly the amount of Ether charged to the
* recipient. This means that the token is essentially pegged to the value of Ether.
*
* The distribution strategy of the gas payment token to users is not defined by this contract. It's a mintable token
* whose only minter is the recipient, so the strategy must be implemented in a derived contract, making use of the
* internal {_mint} function.
*/
contract GSNRecipientERC20Fee is GSNRecipient {
using SafeERC20 for __unstable__ERC20Owned;
using SafeMath for uint256;
enum GSNRecipientERC20FeeErrorCodes {
INSUFFICIENT_BALANCE
}
__unstable__ERC20Owned private _token;
/**
* @dev The arguments to the constructor are the details that the gas payment token will have: `name` and `symbol`. `decimals` is hard-coded to 18.
*/
constructor(string memory name, string memory symbol) {
_token = new __unstable__ERC20Owned(name, symbol);
}
/**
* @dev Returns the gas payment token.
*/
function token() public view virtual returns (__unstable__ERC20Owned) {
return _token;
}
/**
* @dev Internal function that mints the gas payment token. Derived contracts should expose this function in their public API, with proper access control mechanisms.
*/
function _mint(address account, uint256 amount) internal virtual {
token().mint(account, amount);
}
/**
* @dev Ensures that only users with enough gas payment token balance can have transactions relayed through the GSN.
*/
function acceptRelayedCall(
address,
address from,
bytes memory,
uint256 transactionFee,
uint256 gasPrice,
uint256,
uint256,
bytes memory,
uint256 maxPossibleCharge
)
public
view
virtual
override
returns (uint256, bytes memory)
{
if (token().balanceOf(from) < maxPossibleCharge) {
return _rejectRelayedCall(uint256(GSNRecipientERC20FeeErrorCodes.INSUFFICIENT_BALANCE));
}
return _approveRelayedCall(abi.encode(from, maxPossibleCharge, transactionFee, gasPrice));
}
/**
* @dev Implements the precharge to the user. The maximum possible charge (depending on gas limit, gas price, and
* fee) will be deducted from the user balance of gas payment token. Note that this is an overestimation of the
* actual charge, necessary because we cannot predict how much gas the execution will actually need. The remainder
* is returned to the user in {_postRelayedCall}.
*/
function _preRelayedCall(bytes memory context) internal virtual override returns (bytes32) {
(address from, uint256 maxPossibleCharge) = abi.decode(context, (address, uint256));
// The maximum token charge is pre-charged from the user
token().safeTransferFrom(from, address(this), maxPossibleCharge);
return 0;
}
/**
* @dev Returns to the user the extra amount that was previously charged, once the actual execution cost is known.
*/
function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal virtual override {
(address from, uint256 maxPossibleCharge, uint256 transactionFee, uint256 gasPrice) =
abi.decode(context, (address, uint256, uint256, uint256));
// actualCharge is an _estimated_ charge, which assumes postRelayedCall will use all available gas.
// This implementation's gas cost can be roughly estimated as 10k gas, for the two SSTORE operations in an
// ERC20 transfer.
uint256 overestimation = _computeCharge(_POST_RELAYED_CALL_MAX_GAS.sub(10000), gasPrice, transactionFee);
actualCharge = actualCharge.sub(overestimation);
// After the relayed call has been executed and the actual charge estimated, the excess pre-charge is returned
token().safeTransfer(from, maxPossibleCharge.sub(actualCharge));
}
}
/**
* @title __unstable__ERC20Owned
* @dev An ERC20 token owned by another contract, which has minting permissions and can use transferFrom to receive
* anyone's tokens. This contract is an internal helper for GSNRecipientERC20Fee, and should not be used
* outside of this context.
*/
// solhint-disable-next-line contract-name-camelcase
contract __unstable__ERC20Owned is ERC20, Ownable {
uint256 private constant _UINT256_MAX = 2**256 - 1;
constructor(string memory name, string memory symbol) ERC20(name, symbol) { }
// The owner (GSNRecipientERC20Fee) can mint tokens
function mint(address account, uint256 amount) public virtual onlyOwner {
_mint(account, amount);
}
// The owner has 'infinite' allowance for all token holders
function allowance(address tokenOwner, address spender) public view virtual override returns (uint256) {
if (spender == owner()) {
return _UINT256_MAX;
} else {
return super.allowance(tokenOwner, spender);
}
}
// Allowance for the owner cannot be changed (it is always 'infinite')
function _approve(address tokenOwner, address spender, uint256 value) internal virtual override {
if (spender == owner()) {
return;
} else {
super._approve(tokenOwner, spender, value);
}
}
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
if (recipient == owner()) {
_transfer(sender, recipient, amount);
return true;
} else {
return super.transferFrom(sender, recipient, amount);
}
}
}

View File

@ -1,72 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./GSNRecipient.sol";
import "../cryptography/ECDSA.sol";
/**
* @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that allows relayed transactions through when they are
* accompanied by the signature of a trusted signer. The intent is for this signature to be generated by a server that
* performs validations off-chain. Note that nothing is charged to the user in this scheme. Thus, the server should make
* sure to account for this in their economic and threat model.
*/
contract GSNRecipientSignature is GSNRecipient {
using ECDSA for bytes32;
address private _trustedSigner;
enum GSNRecipientSignatureErrorCodes {
INVALID_SIGNER
}
/**
* @dev Sets the trusted signer that is going to be producing signatures to approve relayed calls.
*/
constructor(address trustedSigner) {
require(trustedSigner != address(0), "GSNRecipientSignature: trusted signer is the zero address");
_trustedSigner = trustedSigner;
}
/**
* @dev Ensures that only transactions with a trusted signature can be relayed through the GSN.
*/
function acceptRelayedCall(
address relay,
address from,
bytes memory encodedFunction,
uint256 transactionFee,
uint256 gasPrice,
uint256 gasLimit,
uint256 nonce,
bytes memory approvalData,
uint256
)
public
view
virtual
override
returns (uint256, bytes memory)
{
bytes memory blob = abi.encodePacked(
relay,
from,
encodedFunction,
transactionFee,
gasPrice,
gasLimit,
nonce, // Prevents replays on RelayHub
getHubAddr(), // Prevents replays in multiple RelayHubs
address(this) // Prevents replays in multiple recipients
);
if (keccak256(blob).toEthSignedMessageHash().recover(approvalData) == _trustedSigner) {
return _approveRelayedCall();
} else {
return _rejectRelayedCall(uint256(GSNRecipientSignatureErrorCodes.INVALID_SIGNER));
}
}
function _preRelayedCall(bytes memory) internal virtual override returns (bytes32) { }
function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal virtual override { }
}

View File

@ -1,269 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Interface for `RelayHub`, the core contract of the GSN. Users should not need to interact with this contract
* directly.
*
* See the https://github.com/OpenZeppelin/openzeppelin-gsn-helpers[OpenZeppelin GSN helpers] for more information on
* how to deploy an instance of `RelayHub` on your local test network.
*/
interface IRelayHub {
// Relay management
/**
* @dev Adds stake to a relay and sets its `unstakeDelay`. If the relay does not exist, it is created, and the caller
* of this function becomes its owner. If the relay already exists, only the owner can call this function. A relay
* cannot be its own owner.
*
* All Ether in this function call will be added to the relay's stake.
* Its unstake delay will be assigned to `unstakeDelay`, but the new value must be greater or equal to the current one.
*
* Emits a {Staked} event.
*/
function stake(address relayaddr, uint256 unstakeDelay) external payable;
/**
* @dev Emitted when a relay's stake or unstakeDelay are increased
*/
event Staked(address indexed relay, uint256 stake, uint256 unstakeDelay);
/**
* @dev Registers the caller as a relay.
* The relay must be staked for, and not be a contract (i.e. this function must be called directly from an EOA).
*
* This function can be called multiple times, emitting new {RelayAdded} events. Note that the received
* `transactionFee` is not enforced by {relayCall}.
*
* Emits a {RelayAdded} event.
*/
function registerRelay(uint256 transactionFee, string calldata url) external;
/**
* @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);
/**
* @dev Removes (deregisters) a relay. Unregistered (but staked for) relays can also be removed.
*
* Can only be called by the owner of the relay. After the relay's `unstakeDelay` has elapsed, {unstake} will be
* callable.
*
* Emits a {RelayRemoved} event.
*/
function removeRelayByOwner(address relay) external;
/**
* @dev Emitted when a relay is removed (deregistered). `unstakeTime` is the time when unstake will be callable.
*/
event RelayRemoved(address indexed relay, uint256 unstakeTime);
/** Deletes the relay from the system, and gives back its stake to the owner.
*
* Can only be called by the relay owner, after `unstakeDelay` has elapsed since {removeRelayByOwner} was called.
*
* Emits an {Unstaked} event.
*/
function unstake(address relay) external;
/**
* @dev Emitted when a relay is unstaked for, including the returned stake.
*/
event Unstaked(address indexed relay, uint256 stake);
// States a relay can be in
enum RelayState {
Unknown, // The relay is unknown to the system: it has never been staked for
Staked, // The relay has been staked for, but it is not yet active
Registered, // The relay has registered itself, and is active (can relay calls)
Removed // The relay has been removed by its owner and can no longer relay calls. It must wait for its unstakeDelay to elapse before it can unstake
}
/**
* @dev Returns a relay's status. Note that relays can be deleted when unstaked or penalized, causing this function
* to return an empty entry.
*/
function getRelay(address relay) external view returns (uint256 totalStake, uint256 unstakeDelay, uint256 unstakeTime, address payable owner, RelayState state);
// Balance management
/**
* @dev Deposits Ether for a contract, so that it can receive (and pay for) relayed transactions.
*
* Unused balance can only be withdrawn by the contract itself, by calling {withdraw}.
*
* Emits a {Deposited} event.
*/
function depositFor(address target) external payable;
/**
* @dev Emitted when {depositFor} is called, including the amount and account that was funded.
*/
event Deposited(address indexed recipient, address indexed from, uint256 amount);
/**
* @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);
/**
* Withdraws from an account's balance, sending it back to it. Relay owners call this to retrieve their revenue, and
* contracts can use it to reduce their funding.
*
* Emits a {Withdrawn} event.
*/
function withdraw(uint256 amount, address payable dest) external;
/**
* @dev Emitted when an account withdraws funds from `RelayHub`.
*/
event Withdrawn(address indexed account, address indexed dest, uint256 amount);
// Relaying
/**
* @dev Checks if the `RelayHub` will accept a relayed operation.
* Multiple things must be true for this to happen:
* - all arguments must be signed for by the sender (`from`)
* - the sender's nonce must be the current one
* - the recipient must accept this transaction (via {acceptRelayedCall})
*
* Returns a `PreconditionCheck` value (`OK` when the transaction can be relayed), or a recipient-specific error
* code if it returns one in {acceptRelayedCall}.
*/
function canRelay(
address relay,
address from,
address to,
bytes calldata encodedFunction,
uint256 transactionFee,
uint256 gasPrice,
uint256 gasLimit,
uint256 nonce,
bytes calldata signature,
bytes calldata approvalData
) external view returns (uint256 status, bytes memory recipientContext);
// Preconditions for relaying, checked by canRelay and returned as the corresponding numeric values.
enum PreconditionCheck {
OK, // All checks passed, the call can be relayed
WrongSignature, // The transaction to relay is not signed by requested sender
WrongNonce, // The provided nonce has already been used by the sender
AcceptRelayedCallReverted, // The recipient rejected this call via acceptRelayedCall
InvalidRecipientStatusCode // The recipient returned an invalid (reserved) status code
}
/**
* @dev Relays a transaction.
*
* For this to succeed, multiple conditions must be met:
* - {canRelay} must `return PreconditionCheck.OK`
* - the sender must be a registered relay
* - the transaction's gas price must be larger or equal to the one that was requested by the sender
* - the transaction must have enough gas to not run out of gas if all internal transactions (calls to the
* recipient) use all gas available to them
* - the recipient must have enough balance to pay the relay for the worst-case scenario (i.e. when all gas is
* spent)
*
* If all conditions are met, the call will be relayed and the recipient charged. {preRelayedCall}, the encoded
* function and {postRelayedCall} will be called in that order.
*
* Parameters:
* - `from`: the client originating the request
* - `to`: the target {IRelayRecipient} contract
* - `encodedFunction`: the function call to relay, including data
* - `transactionFee`: fee (%) the relay takes over actual gas cost
* - `gasPrice`: gas price the client is willing to pay
* - `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 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.
*/
function relayCall(
address from,
address to,
bytes calldata encodedFunction,
uint256 transactionFee,
uint256 gasPrice,
uint256 gasLimit,
uint256 nonce,
bytes calldata signature,
bytes calldata approvalData
) external;
/**
* @dev Emitted when an attempt to relay a call failed.
*
* This can happen due to incorrect {relayCall} arguments, or the recipient not accepting the relayed call. The
* actual relayed call was not executed, and the recipient not charged.
*
* The `reason` parameter contains an error code: values 1-10 correspond to `PreconditionCheck` entries, and values
* over 10 are custom recipient error codes returned from {acceptRelayedCall}.
*/
event CanRelayFailed(address indexed relay, address indexed from, address indexed to, bytes4 selector, uint256 reason);
/**
* @dev Emitted when a transaction is relayed.
* Useful when monitoring a relay's operation and relayed calls to a contract
*
* Note that the actual encoded function might be reverted: this is indicated in the `status` parameter.
*
* `charge` is the Ether value deducted from the recipient's balance, paid to the relay's owner.
*/
event TransactionRelayed(address indexed relay, address indexed from, address indexed to, bytes4 selector, RelayCallStatus status, uint256 charge);
// Reason error codes for the TransactionRelayed event
enum RelayCallStatus {
OK, // The transaction was successfully relayed and execution successful - never included in the event
RelayedCallFailed, // The transaction was relayed, but the relayed call failed
PreRelayedFailed, // The transaction was not relayed due to preRelatedCall reverting
PostRelayedFailed, // The transaction was relayed and reverted due to postRelatedCall reverting
RecipientBalanceChanged // The transaction was relayed and reverted due to the recipient's balance changing
}
/**
* @dev Returns how much gas should be forwarded to a call to {relayCall}, in order to relay a transaction that will
* spend up to `relayedCallStipend` gas.
*/
function requiredGas(uint256 relayedCallStipend) external view returns (uint256);
/**
* @dev Returns the maximum recipient charge, given the amount of gas forwarded, gas price and relay fee.
*/
function maxPossibleCharge(uint256 relayedCallStipend, uint256 gasPrice, uint256 transactionFee) external view returns (uint256);
// Relay penalization.
// Any account can penalize relays, removing them from the system immediately, and rewarding the
// reporter with half of the relay's stake. The other half is burned so that, even if the relay penalizes itself, it
// still loses half of its stake.
/**
* @dev Penalize a relay that signed two transactions using the same nonce (making only the first one valid) and
* different data (gas price, gas limit, etc. may be different).
*
* The (unsigned) transaction data and signature for both transactions must be provided.
*/
function penalizeRepeatedNonce(bytes calldata unsignedTx1, bytes calldata signature1, bytes calldata unsignedTx2, bytes calldata signature2) external;
/**
* @dev Penalize a relay that sent a transaction that didn't target ``RelayHub``'s {registerRelay} or {relayCall}.
*/
function penalizeIllegalTransaction(bytes calldata unsignedTx, bytes calldata signature) external;
/**
* @dev Emitted when a relay is penalized.
*/
event Penalized(address indexed relay, address sender, uint256 amount);
/**
* @dev Returns an account's nonce in `RelayHub`.
*/
function getNonce(address from) external view returns (uint256);
}

View File

@ -1,76 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Base interface for a contract that will be called via the GSN from {IRelayHub}.
*
* TIP: You don't need to write an implementation yourself! Inherit from {GSNRecipient} instead.
*/
interface IRelayRecipient {
/**
* @dev Returns the address of the {IRelayHub} instance this recipient interacts with.
*/
function getHubAddr() external view returns (address);
/**
* @dev Called by {IRelayHub} to validate if this recipient accepts being charged for a relayed call. Note that the
* recipient will be charged regardless of the execution result of the relayed call (i.e. if it reverts or not).
*
* The relay request was originated by `from` and will be served by `relay`. `encodedFunction` is the relayed call
* calldata, so its first four bytes are the function selector. The relayed call will be forwarded `gasLimit` gas,
* and the transaction executed with a gas price of at least `gasPrice`. ``relay``'s fee is `transactionFee`, and the
* recipient will be charged at most `maxPossibleCharge` (in wei). `nonce` is the sender's (`from`) nonce for
* replay attack protection in {IRelayHub}, and `approvalData` is a optional parameter that can be used to hold a signature
* over all or some of the previous values.
*
* Returns a tuple, where the first value is used to indicate approval (0) or rejection (custom non-zero error code,
* values 1 to 10 are reserved) and the second one is data to be passed to the other {IRelayRecipient} functions.
*
* {acceptRelayedCall} is called with 50k gas: if it runs out during execution, the request will be considered
* rejected. A regular revert will also trigger a rejection.
*/
function acceptRelayedCall(
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);
/**
* @dev Called by {IRelayHub} on approved relay call requests, before the relayed call is executed. This allows to e.g.
* pre-charge the sender of the transaction.
*
* `context` is the second value returned in the tuple by {acceptRelayedCall}.
*
* Returns a value to be passed to {postRelayedCall}.
*
* {preRelayedCall} is called with 100k gas: if it runs out during 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);
/**
* @dev Called by {IRelayHub} on approved relay call requests, after the relayed call is executed. This allows to e.g.
* charge the user for the relayed call costs, return any overcharges from {preRelayedCall}, or perform
* contract-specific bookkeeping.
*
* `context` is the second value returned in the tuple by {acceptRelayedCall}. `success` is the execution status of
* the relayed call. `actualCharge` is an estimate of how much the recipient will be charged for the transaction,
* not including any gas used by {postRelayedCall} itself. `preRetVal` is {preRelayedCall}'s return value.
*
*
* {postRelayedCall} is called with 100k gas: if it runs out during execution or otherwise reverts, the relayed call
* and the call to {preRelayedCall} will be reverted retroactively, but the recipient will still be charged for the
* transaction's cost.
*/
function postRelayedCall(bytes calldata context, bool success, uint256 actualCharge, bytes32 preRetVal) external;
}

View File

@ -1,31 +0,0 @@
= 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].
The core contract a recipient must inherit from is {GSNRecipient}: it includes all necessary interfaces, as well as some helper methods to make interacting with the GSN easier.
Utilities to make writing xref:ROOT:gsn-strategies.adoc[GSN strategies] easy are available in {GSNRecipient}, or you can simply use one of our pre-made strategies:
* {GSNRecipientERC20Fee} charges the end user for gas costs in an application-specific xref:ROOT:tokens.adoc#ERC20[ERC20 token]
* {GSNRecipientSignature} accepts all relayed calls that have been signed by a trusted third party (e.g. a private key in a backend)
You can also take a look at the two contract interfaces that make up the GSN protocol: {IRelayRecipient} and {IRelayHub}, but you won't need to use those directly.
== Recipient
{{GSNRecipient}}
== Strategies
{{GSNRecipientSignature}}
{{GSNRecipientERC20Fee}}
== Protocol
{{IRelayRecipient}}
{{IRelayHub}}

View File

@ -1,14 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/EnumerableSet.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms.
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
@ -41,12 +54,9 @@ import "../utils/Context.sol";
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context {
using EnumerableSet for EnumerableSet.AddressSet;
using Address for address;
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
EnumerableSet.AddressSet members;
mapping (address => bool) members;
bytes32 adminRole;
}
@ -81,35 +91,19 @@ abstract contract AccessControl is Context {
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId
|| super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view returns (bool) {
return _roles[role].members.contains(account);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view returns (uint256) {
return _roles[role].members.length();
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view returns (address) {
return _roles[role].members.at(index);
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _roles[role].members[account];
}
/**
@ -118,7 +112,7 @@ abstract contract AccessControl is Context {
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view returns (bytes32) {
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return _roles[role].adminRole;
}
@ -132,8 +126,8 @@ abstract contract AccessControl is Context {
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) public virtual {
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
function grantRole(bytes32 role, address account) public virtual override {
require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to grant");
_grantRole(role, account);
}
@ -147,8 +141,8 @@ abstract contract AccessControl is Context {
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) public virtual {
require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
function revokeRole(bytes32 role, address account) public virtual override {
require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to revoke");
_revokeRole(role, account);
}
@ -167,7 +161,7 @@ abstract contract AccessControl is Context {
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual {
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
@ -199,18 +193,20 @@ abstract contract AccessControl is Context {
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
_roles[role].adminRole = adminRole;
}
function _grantRole(bytes32 role, address account) private {
if (_roles[role].members.add(account)) {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) private {
if (_roles[role].members.remove(account)) {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}

View File

@ -0,0 +1,87 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable {
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping (bytes32 => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId
|| super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view override returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Overload {grantRole} to track enumerable memberships
*/
function grantRole(bytes32 role, address account) public virtual override {
super.grantRole(role, account);
_roleMembers[role].add(account);
}
/**
* @dev Overload {revokeRole} to track enumerable memberships
*/
function revokeRole(bytes32 role, address account) public virtual override {
super.revokeRole(role, account);
_roleMembers[role].remove(account);
}
/**
* @dev Overload {renounceRole} to track enumerable memberships
*/
function renounceRole(bytes32 role, address account) public virtual override {
super.renounceRole(role, account);
_roleMembers[role].remove(account);
}
/**
* @dev Overload {_setupRole} to track enumerable memberships
*/
function _setupRole(bytes32 role, address account) internal virtual override {
super._setupRole(role, account);
_roleMembers[role].add(account);
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**

View File

@ -7,7 +7,6 @@ This directory provides ways to restrict who can access the functions of a contr
- {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts.
- {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it.
- {TimelockController} is used in combination with one of the above two mechanisms. By assigning a role to an instance of the `TimelockController` contract, the access to the functions controlled by that role will be delayed by some amount of time.
== Authorization
@ -15,87 +14,4 @@ This directory provides ways to restrict who can access the functions of a contr
{{AccessControl}}
== Timelock
{{TimelockController}}
[[timelock-terminology]]
==== Terminology
* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content.
* *Operation status:*
** *Unset:* An operation that is not part of the timelock mechanism.
** *Pending:* An operation that has been scheduled, before the timer expires.
** *Ready:* An operation that has been scheduled, after the timer expires.
** *Done:* An operation that has been executed.
* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations.
* *Role*:
** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations.
** *Executor:* An address (smart contract or EOA) that is in charge of executing operations.
[[timelock-operation]]
==== Operation structure
Operation executed by the xref:api:access.adoc#TimelockController[`TimelockControler`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations.
Both operations contain:
* *Target*, the address of the smart contract that the timelock should operate on.
* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction.
* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encode using web3js as follows:
```javascript
const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI()
```
* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency.
* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value.
In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length.
[[timelock-operation-lifecycle]]
==== Operation lifecycle
Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle:
`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done`
* By calling xref:api:access.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:access.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:access.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method.
* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed.
* By calling xref:api:access.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:access.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed.
* xref:api:access.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled.
Operations status can be queried using the functions:
* xref:api:access.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`]
* xref:api:access.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`]
* xref:api:access.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`]
[[timelock-roles]]
==== Roles
[[timelock-admin]]
===== Admin
The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, both the timelock and the deployer have this role. After further configuration and testing, the deployer can renounce this role such that all further maintenance operations have to go through the timelock process.
This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5`
[[timelock-proposer]]
===== Proposer
The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO.
WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers.
This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1`
[[timelock-executor]]
===== Executor
The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executor can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers.
This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63`
WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management.
{{AccessControlEnumerable}}

View File

@ -1,16 +0,0 @@
= 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.
The following related EIPs are in draft status and can be found in the drafts directory.
- {EIP712}
== Libraries
{{ECDSA}}
{{MerkleProof}}

View File

@ -1,15 +0,0 @@
= Draft EIPs
This directory contains implementations of EIPs that are still in Draft status.
Due to their nature as drafts, the details of these contracts may change and we cannot guarantee their xref:ROOT:releases-stability.adoc[stability]. Minor releases of OpenZeppelin Contracts may contain breaking changes for the contracts in this directory, which will be duly announced in the https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md[changelog]. The EIPs included here are used by projects in production and this may make them less likely to change significantly.
== Cryptography
{{EIP712}}
== ERC 20
{{IERC20Permit}}
{{ERC20Permit}}

View File

@ -1,10 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Context.sol";
import "../math/SafeMath.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";
import "../utils/math/SafeMath.sol";
/**
* @title PaymentSplitter
@ -20,8 +20,6 @@ import "../utils/Address.sol";
* function.
*/
contract PaymentSplitter is Context {
using SafeMath for uint256;
event PayeeAdded(address account, uint256 shares);
event PaymentReleased(address to, uint256 amount);
event PaymentReceived(address from, uint256 amount);
@ -105,13 +103,13 @@ contract PaymentSplitter is Context {
function release(address payable account) public virtual {
require(_shares[account] > 0, "PaymentSplitter: account has no shares");
uint256 totalReceived = address(this).balance.add(_totalReleased);
uint256 payment = totalReceived.mul(_shares[account]).div(_totalShares).sub(_released[account]);
uint256 totalReceived = address(this).balance + _totalReleased;
uint256 payment = totalReceived * _shares[account] / _totalShares - _released[account];
require(payment != 0, "PaymentSplitter: account is not due payment");
_released[account] = _released[account].add(payment);
_totalReleased = _totalReleased.add(payment);
_released[account] = _released[account] + payment;
_totalReleased = _totalReleased + payment;
Address.sendValue(account, payment);
emit PaymentReleased(account, payment);
@ -129,7 +127,7 @@ contract PaymentSplitter is Context {
_payees.push(account);
_shares[account] = shares_;
_totalShares = _totalShares.add(shares_);
_totalShares = _totalShares + shares_;
emit PayeeAdded(account, shares_);
}
}

View File

@ -0,0 +1,10 @@
= Finance
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/finance
This directory includes primitives for financial systems. We currently only offer the {PaymentSplitter} contract, but we want to grow this directory so we welcome ideas.
== PaymentSplitter
{{PaymentSplitter}}

View File

@ -0,0 +1,91 @@
= Governance
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/governance
This directory includes primitives for on-chain governance. We currently only offer the {TimelockController} contract, that can be used as a component in a governance systems to introduce a delay between a proposal and its execution.
== Timelock
{{TimelockController}}
[[timelock-terminology]]
==== Terminology
* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content.
* *Operation status:*
** *Unset:* An operation that is not part of the timelock mechanism.
** *Pending:* An operation that has been scheduled, before the timer expires.
** *Ready:* An operation that has been scheduled, after the timer expires.
** *Done:* An operation that has been executed.
* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations.
* *Role*:
** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations.
** *Executor:* An address (smart contract or EOA) that is in charge of executing operations.
[[timelock-operation]]
==== Operation structure
Operation executed by the xref:api:governance.adoc#TimelockController[`TimelockControler`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations.
Both operations contain:
* *Target*, the address of the smart contract that the timelock should operate on.
* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction.
* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encode using web3js as follows:
```javascript
const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI()
```
* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency.
* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value.
In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length.
[[timelock-operation-lifecycle]]
==== Operation lifecycle
Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle:
`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done`
* By calling xref:api:governance.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:governance.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:governance.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method.
* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed.
* By calling xref:api:governance.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:governance.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed.
* xref:api:governance.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled.
Operations status can be queried using the functions:
* xref:api:governance.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`]
* xref:api:governance.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`]
* xref:api:governance.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`]
[[timelock-roles]]
==== Roles
[[timelock-admin]]
===== Admin
The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, both the timelock and the deployer have this role. After further configuration and testing, the deployer can renounce this role such that all further maintenance operations have to go through the timelock process.
This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5`
[[timelock-proposer]]
===== Proposer
The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO.
WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers.
This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1`
[[timelock-executor]]
===== Executor
The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executor can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers.
This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63`
WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management.

View File

@ -1,10 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
pragma solidity ^0.8.0;
import "./../math/SafeMath.sol";
import "./AccessControl.sol";
import "../access/AccessControl.sol";
/**
* @dev Contract module which acts as a timelocked controller. When set as the
@ -22,7 +20,6 @@ import "./AccessControl.sol";
* _Available since v3.3._
*/
contract TimelockController is AccessControl {
bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE");
bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");
@ -199,7 +196,7 @@ contract TimelockController is AccessControl {
require(!isOperation(id), "TimelockController: operation already scheduled");
require(delay >= getMinDelay(), "TimelockController: insufficient delay");
// solhint-disable-next-line not-rely-on-time
_timestamps[id] = SafeMath.add(block.timestamp, delay);
_timestamps[id] = block.timestamp + delay;
}
/**

View File

@ -1,31 +0,0 @@
= 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.
There are two main ways to approach this.
* Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`.
* Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts.
Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security.
== Local
{{IERC165}}
{{ERC165}}
{{ERC165Checker}}
== Global
{{IERC1820Registry}}
{{IERC1820Implementer}}
{{ERC1820Implementer}}

View File

@ -1,14 +0,0 @@
= Math
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/math
These are math-related utilities.
== Libraries
{{SafeMath}}
{{SignedSafeMath}}
{{Math}}

View File

@ -1,92 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @title SignedSafeMath
* @dev Signed math operations with safety checks that revert on error.
*/
library SignedSafeMath {
int256 constant private _INT256_MIN = -2**255;
/**
* @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
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");
int256 c = a * b;
require(c / a == b, "SignedSafeMath: multiplication overflow");
return c;
}
/**
* @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");
require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");
int256 c = a / b;
return c;
}
/**
* @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;
require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");
return c;
}
/**
* @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;
require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");
return c;
}
}

View File

@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/*
* @dev Context variant with ERC2771 support.
*/
abstract contract ERC2771Context is Context {
address immutable _trustedForwarder;
constructor(address trustedForwarder) {
_trustedForwarder = trustedForwarder;
}
function isTrustedForwarder(address forwarder) public view virtual returns(bool) {
return forwarder == _trustedForwarder;
}
function _msgSender() internal view virtual override returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) }
} else {
return super._msgSender();
}
}
function _msgData() internal view virtual override returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
return msg.data[:msg.data.length-20];
} else {
return super._msgData();
}
}
}

View File

@ -0,0 +1,58 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/cryptography/ECDSA.sol";
import "../utils/cryptography/draft-EIP712.sol";
/*
* @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}.
*/
contract MinimalForwarder is EIP712 {
using ECDSA for bytes32;
struct ForwardRequest {
address from;
address to;
uint256 value;
uint256 gas;
uint256 nonce;
bytes data;
}
bytes32 private constant TYPEHASH = keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)");
mapping(address => uint256) private _nonces;
constructor() EIP712("MinimalForwarder", "0.0.1") {}
function getNonce(address from) public view returns (uint256) {
return _nonces[from];
}
function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) {
address signer = _hashTypedDataV4(keccak256(abi.encode(
TYPEHASH,
req.from,
req.to,
req.value,
req.gas,
req.nonce,
keccak256(req.data)
))).recover(signature);
return _nonces[req.from] == req.nonce && signer == req.from;
}
function execute(ForwardRequest calldata req, bytes calldata signature) public payable returns (bool, bytes memory) {
require(verify(req, signature), "MinimalForwarder: signature does not match request");
_nonces[req.from] = req.nonce + 1;
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}(abi.encodePacked(req.data, req.from));
// Validate that the relayer has sent enough gas for the call.
// See https://ronan.eth.link/blog/ethereum-gas-dangers/
assert(gasleft() > req.gas / 63);
return (success, returndata);
}
}

View File

@ -0,0 +1,12 @@
= Meta Transactions
[.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx
== Core
{{ERC2771Context}}
== Utils
{{MinimalForwarder}}

View File

@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../access/AccessControlEnumerable.sol";
contract AccessControlEnumerableMock is AccessControlEnumerable {
constructor() {
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
}
function setRoleAdmin(bytes32 roleId, bytes32 adminRoleId) public {
_setRoleAdmin(roleId, adminRoleId);
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../access/AccessControl.sol";

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Address.sol";

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Arrays.sol";

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
pragma solidity ^0.8.0;
contract BadBeaconNoImpl {
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
contract CallReceiverMock {
string public sharedAnswer;

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
/**

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
pragma solidity ^0.8.0;
import "../proxy/Clones.sol";
import "../utils/Address.sol";
@ -11,16 +11,16 @@ contract ClonesMock {
event NewInstance(address instance);
function clone(address master, bytes calldata initdata) public payable {
_initAndEmit(master.clone(), initdata);
function clone(address implementation, bytes calldata initdata) public payable {
_initAndEmit(implementation.clone(), initdata);
}
function cloneDeterministic(address master, bytes32 salt, bytes calldata initdata) public payable {
_initAndEmit(master.cloneDeterministic(salt), initdata);
function cloneDeterministic(address implementation, bytes32 salt, bytes calldata initdata) public payable {
_initAndEmit(implementation.cloneDeterministic(salt), initdata);
}
function predictDeterministicAddress(address master, bytes32 salt) public view returns (address predicted) {
return master.predictDeterministicAddress(salt);
function predictDeterministicAddress(address implementation, bytes32 salt) public view returns (address predicted) {
return implementation.predictDeterministicAddress(salt);
}
function _initAndEmit(address instance, bytes memory initdata) private {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../payment/escrow/ConditionalEscrow.sol";
import "../utils/escrow/ConditionalEscrow.sol";
// mock class using ConditionalEscrow
contract ConditionalEscrowMock is ConditionalEscrow {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Context.sol";

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Counters.sol";

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Create2.sol";
import "../introspection/ERC1820Implementer.sol";
import "../utils/introspection/ERC1820Implementer.sol";
contract Create2Impl {
function deploy(uint256 value, bytes32 salt, bytes memory code) public {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
abstract contract Impl {
function version() public pure virtual returns (string memory);

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../cryptography/ECDSA.sol";
import "../utils/cryptography/ECDSA.sol";
contract ECDSAMock {
using ECDSA for bytes32;

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
pragma solidity ^0.8.0;
import "../drafts/EIP712.sol";
import "../cryptography/ECDSA.sol";
import "../utils/cryptography/draft-EIP712.sol";
import "../utils/cryptography/ECDSA.sol";
contract EIP712External is EIP712 {
constructor(string memory name, string memory version) EIP712(name, version) {}
@ -22,11 +22,7 @@ contract EIP712External is EIP712 {
require(recoveredSigner == signer);
}
function getChainId() external view returns (uint256 chainId) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
// solhint-disable-next-line no-inline-assembly
assembly {
chainId := chainid()
}
function getChainId() external view returns (uint256) {
return block.chainid;
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC1155/ERC1155Burnable.sol";
import "../token/ERC1155/extensions/ERC1155Burnable.sol";
contract ERC1155BurnableMock is ERC1155Burnable {
constructor(string memory uri) ERC1155(uri) { }

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC1155/ERC1155.sol";

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "./ERC1155Mock.sol";
import "../token/ERC1155/ERC1155Pausable.sol";
import "../token/ERC1155/extensions/ERC1155Pausable.sol";
contract ERC1155PausableMock is ERC1155Mock, ERC1155Pausable {
constructor(string memory uri) ERC1155Mock(uri) { }

View File

@ -1,11 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC1155/IERC1155Receiver.sol";
import "./ERC165Mock.sol";
import "../utils/introspection/ERC165.sol";
contract ERC1155ReceiverMock is IERC1155Receiver, ERC165Mock {
contract ERC1155ReceiverMock is IERC1155Receiver, ERC165 {
bytes4 private _recRetval;
bool private _recReverts;
bytes4 private _batRetval;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../../introspection/IERC165.sol";
import "../../utils/introspection/IERC165.sol";
/**
* https://eips.ethereum.org/EIPS/eip-214#specification

View File

@ -0,0 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ERC165MissingData {
function supportsInterface(bytes4 interfaceId) public view {} // missing return
}

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
contract ERC165NotSupported { }

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../introspection/ERC165Checker.sol";
import "../utils/introspection/ERC165Checker.sol";
contract ERC165CheckerMock {
using ERC165Checker for address;

View File

@ -1,11 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../introspection/ERC165.sol";
import "../utils/introspection/ERC165.sol";
contract ERC165Mock is ERC165 {
function registerInterface(bytes4 interfaceId) public {
_registerInterface(interfaceId);
}
}

View File

@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/introspection/ERC165Storage.sol";
contract ERC165StorageMock is ERC165Storage {
function registerInterface(bytes4 interfaceId) public {
_registerInterface(interfaceId);
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../introspection/ERC1820Implementer.sol";
import "../utils/introspection/ERC1820Implementer.sol";
contract ERC1820ImplementerMock is ERC1820Implementer {
function registerInterfaceForAddress(bytes32 interfaceHash, address account) public {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC20/ERC20Burnable.sol";
import "../token/ERC20/extensions/ERC20Burnable.sol";
contract ERC20BurnableMock is ERC20Burnable {
constructor (

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC20/ERC20Capped.sol";
import "../token/ERC20/extensions/ERC20Capped.sol";
contract ERC20CappedMock is ERC20Capped {
constructor (string memory name, string memory symbol, uint256 cap)

View File

@ -1,11 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC20/ERC20.sol";
contract ERC20DecimalsMock is ERC20 {
constructor (string memory name, string memory symbol, uint8 decimals) ERC20(name, symbol) {
_setupDecimals(decimals);
uint8 immutable private _decimals;
constructor (string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) {
_decimals = decimals_;
}
function decimals() public view virtual override returns (uint8) {
return _decimals;
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC20/ERC20.sol";

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC20/ERC20Pausable.sol";
import "../token/ERC20/extensions/ERC20Pausable.sol";
// mock class using ERC20Pausable
contract ERC20PausableMock is ERC20Pausable {

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
pragma solidity ^0.8.0;
import "../drafts/ERC20Permit.sol";
import "../token/ERC20/extensions/draft-ERC20Permit.sol";
contract ERC20PermitMock is ERC20Permit {
constructor (
@ -14,11 +15,7 @@ contract ERC20PermitMock is ERC20Permit {
_mint(initialAccount, initialBalance);
}
function getChainId() external view returns (uint256 chainId) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
// solhint-disable-next-line no-inline-assembly
assembly {
chainId := chainid()
}
function getChainId() external view returns (uint256) {
return block.chainid;
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC20/ERC20Snapshot.sol";
import "../token/ERC20/extensions/ERC20Snapshot.sol";
contract ERC20SnapshotMock is ERC20Snapshot {

View File

@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./ContextMock.sol";
import "../metatx/ERC2771Context.sol";
// By inheriting from ERC2771Context, Context's internal functions are overridden automatically
contract ERC2771ContextMock is ContextMock, ERC2771Context {
constructor(address trustedForwarder) ERC2771Context(trustedForwarder) {}
function _msgSender() internal override(Context, ERC2771Context) view virtual returns (address) {
return ERC2771Context._msgSender();
}
function _msgData() internal override(Context, ERC2771Context) view virtual returns (bytes calldata) {
return ERC2771Context._msgData();
}
}

View File

@ -1,13 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC721/ERC721Burnable.sol";
import "../token/ERC721/extensions/ERC721Burnable.sol";
contract ERC721BurnableMock is ERC721Burnable {
constructor(string memory name, string memory symbol) ERC721(name, symbol) { }
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
}

View File

@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/ERC721Enumerable.sol";
/**
* @title ERC721Mock
* This mock just provides a public safeMint, mint, and burn functions for testing purposes
*/
contract ERC721EnumerableMock is ERC721Enumerable {
string private _baseTokenURI;
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function _baseURI() internal view virtual override returns (string memory) {
return _baseTokenURI;
}
function setBaseURI(string calldata newBaseTokenURI) public {
_baseTokenURI = newBaseTokenURI;
}
function baseURI() public view returns (string memory) {
return _baseURI();
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}

View File

@ -1,30 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../token/ERC721/ERC721.sol";
import "../GSN/GSNRecipient.sol";
import "../GSN/GSNRecipientSignature.sol";
/**
* @title ERC721GSNRecipientMock
* A simple ERC721 mock that has GSN support enabled
*/
contract ERC721GSNRecipientMock is ERC721, GSNRecipient, GSNRecipientSignature {
constructor(string memory name, string memory symbol, address trustedSigner)
ERC721(name, symbol)
GSNRecipientSignature(trustedSigner)
{ }
function mint(uint256 tokenId) public {
_mint(_msgSender(), tokenId);
}
function _msgSender() internal view override(Context, GSNRecipient) returns (address payable) {
return GSNRecipient._msgSender();
}
function _msgData() internal view override(Context, GSNRecipient) returns (bytes memory) {
return GSNRecipient._msgData();
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC721/ERC721.sol";
@ -9,20 +9,26 @@ import "../token/ERC721/ERC721.sol";
* This mock just provides a public safeMint, mint, and burn functions for testing purposes
*/
contract ERC721Mock is ERC721 {
string private _baseTokenURI;
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function _baseURI() internal view virtual override returns (string memory) {
return _baseTokenURI;
}
function setBaseURI(string calldata newBaseTokenURI) public {
_baseTokenURI = newBaseTokenURI;
}
function baseURI() public view returns (string memory) {
return _baseURI();
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function setTokenURI(uint256 tokenId, string memory uri) public {
_setTokenURI(tokenId, uri);
}
function setBaseURI(string memory baseURI) public {
_setBaseURI(baseURI);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC721/ERC721Pausable.sol";
import "../token/ERC721/extensions/ERC721Pausable.sol";
/**
* @title ERC721PausableMock
@ -11,18 +11,6 @@ import "../token/ERC721/ERC721Pausable.sol";
contract ERC721PausableMock is ERC721Pausable {
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function mint(address to, uint256 tokenId) public {
super._mint(to, tokenId);
}
function burn(uint256 tokenId) public {
super._burn(tokenId);
}
function exists(uint256 tokenId) public view returns (bool) {
return super._exists(tokenId);
}
function pause() external {
_pause();
}
@ -30,4 +18,24 @@ contract ERC721PausableMock is ERC721Pausable {
function unpause() external {
_unpause();
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}

View File

@ -1,24 +1,38 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../token/ERC721/IERC721Receiver.sol";
contract ERC721ReceiverMock is IERC721Receiver {
bytes4 private _retval;
bool private _reverts;
enum Error {
None,
RevertWithMessage,
RevertWithoutMessage,
Panic
}
bytes4 private immutable _retval;
Error private immutable _error;
event Received(address operator, address from, uint256 tokenId, bytes data, uint256 gas);
constructor (bytes4 retval, bool reverts) {
constructor (bytes4 retval, Error error) {
_retval = retval;
_reverts = reverts;
_error = error;
}
function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
public override returns (bytes4)
{
require(!_reverts, "ERC721ReceiverMock: reverting");
if (_error == Error.RevertWithMessage) {
revert("ERC721ReceiverMock: reverting");
} else if (_error == Error.RevertWithoutMessage) {
revert();
} else if (_error == Error.Panic) {
uint256 a = uint256(0) / uint256(0);
a;
}
emit Received(operator, from, tokenId, data, gasleft());
return _retval;
}

View File

@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC721/extensions/ERC721URIStorage.sol";
/**
* @title ERC721Mock
* This mock just provides a public safeMint, mint, and burn functions for testing purposes
*/
contract ERC721URIStorageMock is ERC721URIStorage {
string private _baseTokenURI;
constructor (string memory name, string memory symbol) ERC721(name, symbol) { }
function _baseURI() internal view virtual override returns (string memory) {
return _baseTokenURI;
}
function setBaseURI(string calldata newBaseTokenURI) public {
_baseTokenURI = newBaseTokenURI;
}
function baseURI() public view returns (string memory) {
return _baseURI();
}
function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
_setTokenURI(tokenId, _tokenURI);
}
function exists(uint256 tokenId) public view returns (bool) {
return _exists(tokenId);
}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function safeMint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
function safeMint(address to, uint256 tokenId, bytes memory _data) public {
_safeMint(to, tokenId, _data);
}
function burn(uint256 tokenId) public {
_burn(tokenId);
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Context.sol";
import "../token/ERC777/ERC777.sol";

View File

@ -1,13 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Context.sol";
import "../token/ERC777/IERC777.sol";
import "../token/ERC777/IERC777Sender.sol";
import "../token/ERC777/IERC777Recipient.sol";
import "../introspection/IERC1820Registry.sol";
import "../introspection/ERC1820Implementer.sol";
import "../utils/Context.sol";
import "../utils/introspection/IERC1820Registry.sol";
import "../utils/introspection/ERC1820Implementer.sol";
contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer {
event TokensToSendCalled(
@ -150,4 +150,3 @@ contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient,
token.burn(amount, data);
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/EnumerableMap.sol";
import "../utils/structs/EnumerableMap.sol";
contract EnumerableMapMock {
using EnumerableMap for EnumerableMap.UintToAddressMap;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/EnumerableSet.sol";
import "../utils/structs/EnumerableSet.sol";
// Bytes32Set
contract EnumerableBytes32SetMock {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
contract EtherReceiverMock {
bool private _acceptEther;

View File

@ -1,20 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../GSN/GSNRecipient.sol";
import "../GSN/GSNRecipientERC20Fee.sol";
contract GSNRecipientERC20FeeMock is GSNRecipient, GSNRecipientERC20Fee {
constructor(string memory name, string memory symbol) GSNRecipientERC20Fee(name, symbol) { }
function mint(address account, uint256 amount) public {
_mint(account, amount);
}
event MockFunctionCalled(uint256 senderBalance);
function mockFunction() public {
emit MockFunctionCalled(token().balanceOf(_msgSender()));
}
}

View File

@ -1,38 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./ContextMock.sol";
import "../GSN/GSNRecipient.sol";
// By inheriting from GSNRecipient, Context's internal functions are overridden automatically
contract GSNRecipientMock is ContextMock, GSNRecipient {
function withdrawDeposits(uint256 amount, address payable payee) public {
_withdrawDeposits(amount, payee);
}
function acceptRelayedCall(address, address, bytes calldata, uint256, uint256, uint256, uint256, bytes calldata, uint256)
external
pure
override
returns (uint256, bytes memory)
{
return (0, "");
}
function _preRelayedCall(bytes memory) internal override returns (bytes32) { }
function _postRelayedCall(bytes memory, bool, uint256, bytes32) internal override { }
function upgradeRelayHub(address newRelayHub) public {
return _upgradeRelayHub(newRelayHub);
}
function _msgSender() internal override(Context, GSNRecipient) view virtual returns (address payable) {
return GSNRecipient._msgSender();
}
function _msgData() internal override(Context, GSNRecipient) view virtual returns (bytes memory) {
return GSNRecipient._msgData();
}
}

View File

@ -1,16 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../GSN/GSNRecipient.sol";
import "../GSN/GSNRecipientSignature.sol";
contract GSNRecipientSignatureMock is GSNRecipient, GSNRecipientSignature {
constructor(address trustedSigner) GSNRecipientSignature(trustedSigner) { }
event MockFunctionCalled();
function mockFunction() public {
emit MockFunctionCalled();
}
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../proxy/Initializable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @title InitializableMock

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../math/Math.sol";
import "../utils/math/Math.sol";
contract MathMock {
function max(uint256 a, uint256 b) public pure returns (uint256) {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import { MerkleProof } from "../cryptography/MerkleProof.sol";
import "../utils/cryptography/MerkleProof.sol";
contract MerkleProofWrapper {
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) public pure returns (bool) {

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../proxy/Initializable.sol";
import "../proxy/utils/Initializable.sol";
// Sample contracts showing upgradeability with multiple inheritance.
// Child contract inherits from Father and Mother contracts, and Father extends from Gramps.
//
//
// Human
// / \
// | Gramps

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../access/Ownable.sol";

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Pausable.sol";
import "../security/Pausable.sol";
contract PausableMock is Pausable {
bool public drasticMeasureTaken;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../payment/PullPayment.sol";
import "../security/PullPayment.sol";
// mock class using PullPayment
contract PullPaymentMock is PullPayment {

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Context.sol";
contract ReentrancyAttack is Context {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/ReentrancyGuard.sol";
import "../security/ReentrancyGuard.sol";
import "./ReentrancyAttack.sol";
contract ReentrancyMock is ReentrancyGuard {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../proxy/Initializable.sol";
import "../proxy/utils/Initializable.sol";
contract Implementation1 is Initializable {
uint internal _value;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/SafeCast.sol";
import "../utils/math/SafeCast.sol";
contract SafeCastMock {
using SafeCast for uint;

View File

@ -1,10 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Context.sol";
import "../token/ERC20/IERC20.sol";
import "../token/ERC20/SafeERC20.sol";
import "../token/ERC20/utils/SafeERC20.sol";
contract ERC20ReturnFalseMock is Context {
uint256 private _allowance;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../math/SafeMath.sol";
import "../utils/math/SafeMath.sol";
contract SafeMathMock {
function tryAdd(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
@ -25,23 +25,25 @@ contract SafeMathMock {
return SafeMath.tryMod(a, b);
}
function add(uint256 a, uint256 b) public pure returns (uint256) {
// using the do* naming convention to avoid warnings due to clashing opcode names
function doAdd(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.add(a, b);
}
function sub(uint256 a, uint256 b) public pure returns (uint256) {
function doSub(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.sub(a, b);
}
function mul(uint256 a, uint256 b) public pure returns (uint256) {
function doMul(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.mul(a, b);
}
function div(uint256 a, uint256 b) public pure returns (uint256) {
function doDiv(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.div(a, b);
}
function mod(uint256 a, uint256 b) public pure returns (uint256) {
function doMod(uint256 a, uint256 b) public pure returns (uint256) {
return SafeMath.mod(a, b);
}

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../math/SignedSafeMath.sol";
import "../utils/math/SignedSafeMath.sol";
contract SignedSafeMathMock {
function mul(int256 a, int256 b) public pure returns (int256) {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../proxy/Initializable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @title MigratableMockV1

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "../utils/Strings.sol";
@ -8,4 +8,10 @@ contract StringsMock {
function fromUint256(uint256 value) public pure returns (string memory) {
return Strings.toString(value);
}
function fromUint256Hex(uint256 value) public pure returns (string memory) {
return Strings.toHexString(value);
}
function fromUint256HexFixed(uint256 value, uint256 length) public pure returns (string memory) {
return Strings.toHexString(value, length);
}
}

View File

@ -1,12 +1,11 @@
{
"name": "@openzeppelin/contracts",
"description": "Secure Smart Contract library for Solidity",
"version": "3.3.0-solc-0.7",
"version": "4.0.0",
"files": [
"**/*.sol",
"/build/contracts/*.json",
"!/mocks",
"!/examples"
"!/mocks/**/*"
],
"scripts": {
"prepare": "bash ../scripts/prepare-contracts-package.sh",

View File

@ -1,22 +0,0 @@
= 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].
== Utilities
{{PaymentSplitter}}
{{PullPayment}}
== Escrow
{{Escrow}}
{{ConditionalEscrow}}
{{RefundEscrow}}

View File

@ -1,22 +0,0 @@
= 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**.
TIP: Intermediate and advanced users can use these as starting points when writing their own contracts, extending them with custom functionality as they see fit.
== Tokens
{{ERC20PresetMinterPauser}}
{{ERC721PresetMinterPauserAutoId}}
{{ERC1155PresetMinterPauser}}
{{ERC20PresetFixedSupply}}
{{ERC777PresetFixedSupply}}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
pragma solidity ^0.8.0;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
@ -12,19 +12,21 @@ pragma solidity >=0.6.0 <0.8.0;
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*
* _Available since v3.4._
*/
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address master) internal returns (address instance) {
function clone(address implementation) internal returns (address instance) {
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, master))
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create(0, ptr, 0x37)
}
@ -32,18 +34,18 @@ library Clones {
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `master` and `salt` multiple time will revert, since
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address master, bytes32 salt) internal returns (address instance) {
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, master))
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
instance := create2(0, ptr, 0x37, salt)
}
@ -53,12 +55,12 @@ library Clones {
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address master, bytes32 salt, address deployer) internal pure returns (address predicted) {
function predictDeterministicAddress(address implementation, bytes32 salt, address deployer) internal pure returns (address predicted) {
// solhint-disable-next-line no-inline-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(ptr, 0x14), shl(0x60, master))
mstore(add(ptr, 0x14), shl(0x60, implementation))
mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
mstore(add(ptr, 0x38), shl(0x60, deployer))
mstore(add(ptr, 0x4c), salt)
@ -70,7 +72,7 @@ library Clones {
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address master, bytes32 salt) internal view returns (address predicted) {
return predictDeterministicAddress(master, salt, address(this));
function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
import "./Proxy.sol";
import "../utils/Address.sol";
import "../Proxy.sol";
import "../../utils/Address.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
@ -14,7 +14,7 @@ import "../utils/Address.sol";
* Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see
* {TransparentUpgradeableProxy}.
*/
contract UpgradeableProxy is Proxy {
contract ERC1967Proxy is Proxy {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
*
@ -66,7 +66,7 @@ contract UpgradeableProxy is Proxy {
* @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");
require(Address.isContract(newImplementation), "ERC1967Proxy: new implementation is not a contract");
bytes32 slot = _IMPLEMENTATION_SLOT;

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM

View File

@ -7,22 +7,28 @@ This is a low-level set of contracts implementing different proxy patterns with
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.
{ERC1967Proxy} provides a simple, fully functioning, proxy. While this proxy is not by itself upgradeable, it includes 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.
An alternative upgradeability mechanism is provided in <<Beacon>>. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. In this pattern, the proxy contract doesn't hold the implementation address in storage like {UpgradeableProxy}, but the address of a {UpgradeableBeacon} contract, which is where the implementation address is actually stored and retrieved from. The `upgrade` operations that change the implementation contract address are then sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded.
The {Clones} library provides a way to deploy minimal non-upgradeable proxies for cheap. This can be useful for applications that require deploying many instances of the same contract (for example one per user, or one per task). These instances are designed to be both cheap to deploy, and cheap to call. The drawback being that they are not upgradeable.
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.
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 Hardhat.
== Core
{{Proxy}}
{{UpgradeableProxy}}
== ERC1967
{{ERC1967Proxy}}
== Transparent Proxy
{{TransparentUpgradeableProxy}}
{{ProxyAdmin}}
== Beacon
{{BeaconProxy}}
@ -35,8 +41,6 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th
{{Clones}}
== Utilities
== Utils
{{Initializable}}
{{ProxyAdmin}}

Some files were not shown because too many files have changed in this diff Show More