Parcourir la source

Merge branch 'solc-0.7' into solc-0.8

Hadrien Croubois il y a 4 ans
Parent
commit
0db76e98f9
77 fichiers modifiés avec 1780 ajouts et 1328 suppressions
  1. 15 17
      .github/PULL_REQUEST_TEMPLATE.md
  2. 3 2
      .github/workflows/test.yml
  3. 21 0
      CHANGELOG.md
  4. 1 1
      README.md
  5. 1 20
      contracts/GSN/Context.sol
  6. 10 10
      contracts/GSN/GSNRecipient.sol
  7. 10 10
      contracts/GSN/GSNRecipientERC20Fee.sol
  8. 1 1
      contracts/access/AccessControl.sol
  9. 3 3
      contracts/access/Ownable.sol
  10. 23 12
      contracts/access/TimelockController.sol
  11. 2 2
      contracts/drafts/EIP712.sol
  12. 3 3
      contracts/drafts/ERC20Permit.sol
  13. 2 2
      contracts/drafts/IERC20Permit.sol
  14. 1 1
      contracts/introspection/ERC165.sol
  15. 23 0
      contracts/introspection/ERC165Checker.sol
  16. 1 1
      contracts/introspection/ERC1820Implementer.sol
  17. 127 4
      contracts/math/SafeMath.sol
  18. 32 0
      contracts/mocks/ClonesMock.sol
  19. 1 1
      contracts/mocks/ContextMock.sol
  20. 4 0
      contracts/mocks/ERC165CheckerMock.sol
  21. 7 1
      contracts/mocks/ERC777Mock.sol
  22. 4 1
      contracts/mocks/ERC777SenderRecipientMock.sol
  23. 8 0
      contracts/mocks/EnumerableMapMock.sol
  24. 1 1
      contracts/mocks/GSNRecipientMock.sol
  25. 1 1
      contracts/mocks/ReentrancyAttack.sol
  26. 1 1
      contracts/mocks/SafeERC20Helper.sol
  27. 84 6
      contracts/mocks/SafeMathMock.sol
  28. 1 1
      contracts/package.json
  29. 4 2
      contracts/payment/PaymentSplitter.sol
  30. 1 1
      contracts/payment/escrow/Escrow.sol
  31. 11 9
      contracts/payment/escrow/RefundEscrow.sol
  32. 1 1
      contracts/presets/ERC1155PresetMinterPauser.sol
  33. 1 1
      contracts/presets/ERC20PresetFixedSupply.sol
  34. 1 1
      contracts/presets/ERC20PresetMinterPauser.sol
  35. 1 1
      contracts/presets/ERC721PresetMinterPauserAutoId.sol
  36. 1 1
      contracts/presets/ERC777PresetFixedSupply.sol
  37. 4 4
      contracts/proxy/BeaconProxy.sol
  38. 76 0
      contracts/proxy/Clones.sol
  39. 4 12
      contracts/proxy/Initializable.sol
  40. 10 10
      contracts/proxy/Proxy.sol
  41. 15 15
      contracts/proxy/ProxyAdmin.sol
  42. 9 3
      contracts/proxy/README.adoc
  43. 18 20
      contracts/proxy/TransparentUpgradeableProxy.sol
  44. 2 2
      contracts/proxy/UpgradeableBeacon.sol
  45. 6 8
      contracts/proxy/UpgradeableProxy.sol
  46. 8 7
      contracts/token/ERC1155/ERC1155.sol
  47. 3 1
      contracts/token/ERC1155/ERC1155Pausable.sol
  48. 7 7
      contracts/token/ERC20/ERC20.sol
  49. 1 1
      contracts/token/ERC20/ERC20Burnable.sol
  50. 1 1
      contracts/token/ERC20/ERC20Capped.sol
  51. 2 2
      contracts/token/ERC20/ERC20Snapshot.sol
  52. 6 6
      contracts/token/ERC20/TokenTimelock.sol
  53. 25 25
      contracts/token/ERC721/ERC721.sol
  54. 1 1
      contracts/token/ERC721/ERC721Burnable.sol
  55. 2 2
      contracts/token/ERC721/IERC721.sol
  56. 28 26
      contracts/token/ERC777/ERC777.sol
  57. 24 0
      contracts/utils/Context.sol
  58. 28 1
      contracts/utils/EnumerableMap.sol
  59. 4 4
      contracts/utils/Pausable.sol
  60. 2 2
      docs/modules/ROOT/pages/access-control.adoc
  61. 1 1
      docs/modules/ROOT/pages/erc20-supply.adoc
  62. 1 1
      docs/modules/ROOT/pages/erc20.adoc
  63. 0 1
      docs/modules/ROOT/pages/erc777.adoc
  64. 1 1
      docs/modules/ROOT/pages/gsn-strategies.adoc
  65. 1 1
      docs/modules/ROOT/pages/index.adoc
  66. 389 960
      package-lock.json
  67. 1 1
      package.json
  68. 1 1
      scripts/prepare-docs.sh
  69. 52 0
      test/introspection/ERC165Checker.test.js
  70. 332 75
      test/math/SafeMath.test.js
  71. 150 0
      test/proxy/Clones.behaviour.js
  72. 54 0
      test/proxy/Clones.test.js
  73. 7 3
      test/proxy/TransparentUpgradeableProxy.behaviour.js
  74. 18 2
      test/proxy/UpgradeableProxy.behaviour.js
  75. 1 1
      test/token/ERC1155/ERC1155.behavior.js
  76. 33 0
      test/token/ERC777/ERC777.test.js
  77. 40 1
      test/utils/EnumerableMap.test.js

+ 15 - 17
.github/PULL_REQUEST_TEMPLATE.md

@@ -1,22 +1,20 @@
-<!-- 0. 🎉 Thank you for submitting a PR! -->
+<!-- Thank you for your interest in contributing to OpenZeppelin! -->
 
-<!-- 1. Does this close any open issues? Please list them below. -->
+<!-- Consider opening an issue for discussion prior to submitting a PR. -->
+<!-- New features will be merged faster if they were first discussed and designed with the team. -->
 
-<!-- Keep in mind that new features have a better chance of being merged fast if
-they were first discussed and designed with the maintainers. If there is no
-corresponding issue, please consider opening one for discussion first! -->
+Fixes #???? <!-- Fill in with issue number -->
 
-Fixes #
+<!-- Describe the changes introduced in this pull request. -->
+<!-- Include any context necessary for understanding the PR's purpose. -->
 
-<!-- 2. Describe the changes introduced in this pull request. -->
-<!--    Include any context necessary for understanding the PR's purpose. -->
 
-<!-- 3. Before submitting, please make sure that you have:
-  - reviewed the OpenZeppelin Contributor Guidelines
-    (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CONTRIBUTING.md),
-  - added tests where applicable to test new functionality,
-  - made sure that your contracts are well-documented,
-  - run the Solidity linter (`npm run lint:sol`) and fixed any issues,
-  - run the JS linter and fixed any issues (`npm run lint:fix`), and
-  - updated the changelog, if applicable.
--->
+#### PR Checklist
+
+<!-- Before merging the pull request all of the following must be complete. -->
+<!-- Feel free to submit a PR or Draft PR even if some items are pending. -->
+<!-- Some of the items may not apply. -->
+
+- [ ] Tests
+- [ ] Documentation
+- [ ] Changelog entry

+ 3 - 2
.github/workflows/test.yml

@@ -6,13 +6,14 @@ on:
       - master
       - release-v*
   pull_request: {}
+  workflow_dispatch: {}
 
 jobs:
   test:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
+      - uses: actions/setup-node@v2
         with:
           node-version: 10.x
       - uses: actions/cache@v2
@@ -30,7 +31,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
-      - uses: actions/setup-node@v1
+      - uses: actions/setup-node@v2
         with:
           node-version: 10.x
       - uses: actions/cache@v2

+ 21 - 0
CHANGELOG.md

@@ -7,6 +7,21 @@
  * `ERC20Permit`: added an implementation of the ERC20 permit extension for gasless token approvals. ([#2237](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237))
  * Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399))
  * `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333))
+ * `Clones`: added a library for deploying EIP 1167 minimal proxies. ([#2449](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2449))
+ * `Context`: moved from `contracts/GSN` to `contracts/utils`. ([#2453](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2453))
+ * `PaymentSplitter`: replace usage of `.transfer()` with `Address.sendValue` for improved compatibility with smart wallets. ([#2455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2455))
+ * `UpgradeableProxy`: bubble revert reasons from initialization calls. ([#2454](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2454))
+ * `SafeMath`: fix a memory allocation issue by adding new `SafeMath.tryOp(uint,uint)→(bool,uint)` functions. `SafeMath.op(uint,uint,string)→uint` are now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462))
+ * `EnumerableMap`: fix a memory allocation issue by adding new `EnumerableMap.tryGet(uint)→(bool,address)` functions. `EnumerableMap.get(uint)→string` is now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462))
+ * `ERC165Checker`: added batch `getSupportedInterfaces`. ([#2469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2469))
+ * `RefundEscrow`: `beneficiaryWithdraw` will forward all available gas to the beneficiary. ([#2480](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2480))
+ * Many view and pure functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior.
+
+### Security Fixes
+
+ * `ERC777`: fix potential reentrancy issues for custom extensions to `ERC777`. ([#2483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483))
+
+If you're using our implementation of ERC777 from version 3.3.0 or earlier, and you define a custom `_beforeTokenTransfer` function that writes to a storage variable, you may be vulnerable to a reentrancy attack. If you're affected and would like assistance please write to security@openzeppelin.com. [Read more in the pull request.](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483)
 
 ## 3.3.0 (2020-11-26)
 
@@ -15,6 +30,12 @@
  * `TimelockController`: added a contract to augment access control schemes with a delay. ([#2354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2354))
  * `EnumerableSet`: added `Bytes32Set`, for sets of `bytes32`. ([#2395](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2395))
 
+## 3.2.2-solc-0.7 (2020-10-28)
+ * Resolve warnings introduced by Solidity 0.7.4. ([#2396](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2396))
+
+## 3.2.1-solc-0.7 (2020-09-15)
+ * `ERC777`: Remove a warning about function state visibility in Solidity 0.7. ([#2327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2327))
+
 ## 3.2.0 (2020-09-10)
 
 ### New features

+ 1 - 1
README.md

@@ -32,7 +32,7 @@ pragma solidity ^0.8.0;
 import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
 
 contract MyCollectible is ERC721 {
-    constructor() ERC721("MyCollectible", "MCO") public {
+    constructor() ERC721("MyCollectible", "MCO") {
     }
 }
 ```

+ 1 - 20
contracts/GSN/Context.sol

@@ -2,23 +2,4 @@
 
 pragma solidity ^0.8.0;
 
-/*
- * @dev Provides information about the current execution context, including the
- * sender of the transaction and its data. While these are generally available
- * via msg.sender and msg.data, they should not be accessed in such a direct
- * manner, since when dealing with GSN meta-transactions the account sending and
- * paying for execution may not be the actual sender (as far as an application
- * is concerned).
- *
- * This contract is only required for intermediate, library-like contracts.
- */
-abstract contract Context {
-    function _msgSender() internal view virtual returns (address) {
-        return msg.sender;
-    }
-
-    function _msgData() internal view virtual returns (bytes memory) {
-        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
-        return msg.data;
-    }
-}
+import "../utils/Context.sol";

+ 10 - 10
contracts/GSN/GSNRecipient.sol

@@ -2,9 +2,9 @@
 
 pragma solidity ^0.8.0;
 
+import "../utils/Context.sol";
 import "./IRelayRecipient.sol";
 import "./IRelayHub.sol";
-import "./Context.sol";
 
 /**
  * @dev Base GSN recipient contract: includes the {IRelayRecipient} interface
@@ -35,7 +35,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
     /**
      * @dev Returns the address of the {IRelayHub} contract for this recipient.
      */
-    function getHubAddr() public view override returns (address) {
+    function getHubAddr() public view virtual override returns (address) {
         return _relayHub;
     }
 
@@ -62,7 +62,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
      */
     // This function is view for future-proofing, it may require reading from
     // storage in the future.
-    function relayHubVersion() public view returns (string memory) {
+    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";
     }
@@ -73,7 +73,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
      * Derived contracts should expose this in an external interface with proper access control.
      */
     function _withdrawDeposits(uint256 amount, address payable payee) internal virtual {
-        IRelayHub(_relayHub).withdraw(amount, payee);
+        IRelayHub(getHubAddr()).withdraw(amount, payee);
     }
 
     // Overrides for Context's functions: when called from RelayHub, sender and
@@ -88,7 +88,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
      * IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead.
      */
     function _msgSender() internal view virtual override returns (address) {
-        if (msg.sender != _relayHub) {
+        if (msg.sender != getHubAddr()) {
             return msg.sender;
         } else {
             return _getRelayedCallSender();
@@ -102,7 +102,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
      * 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 != _relayHub) {
+        if (msg.sender != getHubAddr()) {
             return msg.data;
         } else {
             return _getRelayedCallData();
@@ -162,7 +162,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
      * @dev Return this in acceptRelayedCall to proceed with the execution of a relayed call. Note that this contract
      * will be charged a fee by RelayHub
      */
-    function _approveRelayedCall() internal pure returns (uint256, bytes memory) {
+    function _approveRelayedCall() internal pure virtual returns (uint256, bytes memory) {
         return _approveRelayedCall("");
     }
 
@@ -171,14 +171,14 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
      *
      * This overload forwards `context` to _preRelayedCall and _postRelayedCall.
      */
-    function _approveRelayedCall(bytes memory context) internal pure returns (uint256, bytes memory) {
+    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 returns (uint256, bytes memory) {
+    function _rejectRelayedCall(uint256 errorCode) internal pure virtual returns (uint256, bytes memory) {
         return (_RELAYED_CALL_REJECTED + errorCode, "");
     }
 
@@ -186,7 +186,7 @@ abstract contract GSNRecipient is IRelayRecipient, Context {
      * @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 returns (uint256) {
+    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;

+ 10 - 10
contracts/GSN/GSNRecipientERC20Fee.sol

@@ -35,15 +35,15 @@ contract GSNRecipientERC20Fee is GSNRecipient {
     /**
      * @dev Returns the gas payment token.
      */
-    function token() public view returns (IERC20) {
-        return IERC20(_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);
+        token().mint(account, amount);
     }
 
     /**
@@ -66,7 +66,7 @@ contract GSNRecipientERC20Fee is GSNRecipient {
         override
         returns (uint256, bytes memory)
     {
-        if (_token.balanceOf(from) < maxPossibleCharge) {
+        if (token().balanceOf(from) < maxPossibleCharge) {
             return _rejectRelayedCall(uint256(GSNRecipientERC20FeeErrorCodes.INSUFFICIENT_BALANCE));
         }
 
@@ -83,7 +83,7 @@ contract GSNRecipientERC20Fee is GSNRecipient {
         (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);
+        token().safeTransferFrom(from, address(this), maxPossibleCharge);
 
         return 0;
     }
@@ -102,7 +102,7 @@ contract GSNRecipientERC20Fee is GSNRecipient {
         actualCharge = actualCharge - overestimation;
 
         // After the relayed call has been executed and the actual charge estimated, the excess pre-charge is returned
-        _token.safeTransfer(from, maxPossibleCharge - actualCharge);
+        token().safeTransfer(from, maxPossibleCharge - actualCharge);
     }
 }
 
@@ -119,12 +119,12 @@ contract __unstable__ERC20Owned is ERC20, Ownable {
     constructor(string memory name, string memory symbol) ERC20(name, symbol) { }
 
     // The owner (GSNRecipientERC20Fee) can mint tokens
-    function mint(address account, uint256 amount) public onlyOwner {
+    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 override returns (uint256) {
+    function allowance(address tokenOwner, address spender) public view virtual override returns (uint256) {
         if (spender == owner()) {
             return _UINT256_MAX;
         } else {
@@ -133,7 +133,7 @@ contract __unstable__ERC20Owned is ERC20, Ownable {
     }
 
     // Allowance for the owner cannot be changed (it is always 'infinite')
-    function _approve(address tokenOwner, address spender, uint256 value) internal override {
+    function _approve(address tokenOwner, address spender, uint256 value) internal virtual override {
         if (spender == owner()) {
             return;
         } else {
@@ -141,7 +141,7 @@ contract __unstable__ERC20Owned is ERC20, Ownable {
         }
     }
 
-    function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
+    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
         if (recipient == owner()) {
             _transfer(sender, recipient, amount);
             return true;

+ 1 - 1
contracts/access/AccessControl.sol

@@ -4,7 +4,7 @@ pragma solidity ^0.8.0;
 
 import "../utils/EnumerableSet.sol";
 import "../utils/Address.sol";
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 
 /**
  * @dev Contract module that allows children to implement role-based access

+ 3 - 3
contracts/access/Ownable.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 /**
  * @dev Contract module which provides a basic access control mechanism, where
  * there is an account (an owner) that can be granted exclusive access to
@@ -32,7 +32,7 @@ abstract contract Ownable is Context {
     /**
      * @dev Returns the address of the current owner.
      */
-    function owner() public view returns (address) {
+    function owner() public view virtual returns (address) {
         return _owner;
     }
 
@@ -40,7 +40,7 @@ abstract contract Ownable is Context {
      * @dev Throws if called by any account other than the owner.
      */
     modifier onlyOwner() {
-        require(_owner == _msgSender(), "Ownable: caller is not the owner");
+        require(owner() == _msgSender(), "Ownable: caller is not the owner");
         _;
     }
 

+ 23 - 12
contracts/access/TimelockController.sol

@@ -16,6 +16,8 @@ import "./AccessControl.sol";
  * is in charge of proposing (resp executing) operations. A common use case is
  * to position this {TimelockController} as the owner of a smart contract, with
  * a multisig or a DAO as the sole proposer.
+ *
+ * _Available since v3.3._
  */
 contract TimelockController is AccessControl {
 
@@ -89,33 +91,42 @@ contract TimelockController is AccessControl {
      */
     receive() external payable {}
 
+    /**
+     * @dev Returns whether an id correspond to a registered operation. This
+     * includes both Pending, Ready and Done operations.
+     */
+    function isOperation(bytes32 id) public view virtual returns (bool pending) {
+        return getTimestamp(id) > 0;
+    }
+
     /**
      * @dev Returns whether an operation is pending or not.
      */
-    function isOperationPending(bytes32 id) public view returns (bool pending) {
-        return _timestamps[id] > _DONE_TIMESTAMP;
+    function isOperationPending(bytes32 id) public view virtual returns (bool pending) {
+        return getTimestamp(id) > _DONE_TIMESTAMP;
     }
 
     /**
      * @dev Returns whether an operation is ready or not.
      */
-    function isOperationReady(bytes32 id) public view returns (bool ready) {
+    function isOperationReady(bytes32 id) public view virtual returns (bool ready) {
+        uint256 timestamp = getTimestamp(id);
         // solhint-disable-next-line not-rely-on-time
-        return _timestamps[id] > _DONE_TIMESTAMP && _timestamps[id] <= block.timestamp;
+        return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp;
     }
 
     /**
      * @dev Returns whether an operation is done or not.
      */
-    function isOperationDone(bytes32 id) public view returns (bool done) {
-        return _timestamps[id] == _DONE_TIMESTAMP;
+    function isOperationDone(bytes32 id) public view virtual returns (bool done) {
+        return getTimestamp(id) == _DONE_TIMESTAMP;
     }
 
     /**
      * @dev Returns the timestamp at with an operation becomes ready (0 for
      * unset operations, 1 for done operations).
      */
-    function getTimestamp(bytes32 id) public view returns (uint256 timestamp) {
+    function getTimestamp(bytes32 id) public view virtual returns (uint256 timestamp) {
         return _timestamps[id];
     }
 
@@ -124,7 +135,7 @@ contract TimelockController is AccessControl {
      *
      * This value can be changed by executing an operation that calls `updateDelay`.
      */
-    function getMinDelay() public view returns (uint256 duration) {
+    function getMinDelay() public view virtual returns (uint256 duration) {
         return _minDelay;
     }
 
@@ -132,7 +143,7 @@ contract TimelockController is AccessControl {
      * @dev Returns the identifier of an operation containing a single
      * transaction.
      */
-    function hashOperation(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) public pure returns (bytes32 hash) {
+    function hashOperation(address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt) public pure virtual returns (bytes32 hash) {
         return keccak256(abi.encode(target, value, data, predecessor, salt));
     }
 
@@ -140,7 +151,7 @@ contract TimelockController is AccessControl {
      * @dev Returns the identifier of an operation containing a batch of
      * transactions.
      */
-    function hashOperationBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt) public pure returns (bytes32 hash) {
+    function hashOperationBatch(address[] calldata targets, uint256[] calldata values, bytes[] calldata datas, bytes32 predecessor, bytes32 salt) public pure virtual returns (bytes32 hash) {
         return keccak256(abi.encode(targets, values, datas, predecessor, salt));
     }
 
@@ -183,8 +194,8 @@ contract TimelockController is AccessControl {
      * @dev Schedule an operation that is to becomes valid after a given delay.
      */
     function _schedule(bytes32 id, uint256 delay) private {
-        require(_timestamps[id] == 0, "TimelockController: operation already scheduled");
-        require(delay >= _minDelay, "TimelockController: insufficient delay");
+        require(!isOperation(id), "TimelockController: operation already scheduled");
+        require(delay >= getMinDelay(), "TimelockController: insufficient delay");
         // solhint-disable-next-line not-rely-on-time
         _timestamps[id] = block.timestamp + delay;
     }

+ 2 - 2
contracts/drafts/EIP712.sol

@@ -46,7 +46,7 @@ abstract contract EIP712 {
     constructor(string memory name, string memory version) {
         bytes32 hashedName = keccak256(bytes(name));
         bytes32 hashedVersion = keccak256(bytes(version));
-        bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); 
+        bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
         _HASHED_NAME = hashedName;
         _HASHED_VERSION = hashedVersion;
         _CACHED_CHAIN_ID = block.chainid;
@@ -92,7 +92,7 @@ abstract contract EIP712 {
      * address signer = ECDSA.recover(digest, signature);
      * ```
      */
-    function _hashTypedDataV4(bytes32 structHash) internal view returns (bytes32) {
+    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
         return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
     }
 }

+ 3 - 3
contracts/drafts/ERC20Permit.sol

@@ -35,7 +35,7 @@ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
     /**
      * @dev See {IERC20Permit-permit}.
      */
-    function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual override {
+    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual override {
         // solhint-disable-next-line not-rely-on-time
         require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
 
@@ -44,7 +44,7 @@ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
                 _PERMIT_TYPEHASH,
                 owner,
                 spender,
-                amount,
+                value,
                 _nonces[owner].current(),
                 deadline
             )
@@ -56,7 +56,7 @@ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
         require(signer == owner, "ERC20Permit: invalid signature");
 
         _nonces[owner].increment();
-        _approve(owner, spender, amount);
+        _approve(owner, spender, value);
     }
 
     /**

+ 2 - 2
contracts/drafts/IERC20Permit.sol

@@ -12,7 +12,7 @@ pragma solidity ^0.8.0;
  */
 interface IERC20Permit {
     /**
-     * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,
+     * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,
      * given `owner`'s signed approval.
      *
      * IMPORTANT: The same issues {IERC20-approve} has related to transaction
@@ -32,7 +32,7 @@ interface IERC20Permit {
      * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
      * section].
      */
-    function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
+    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;
 
     /**
      * @dev Returns the current nonce for `owner`. This value must be

+ 1 - 1
contracts/introspection/ERC165.sol

@@ -32,7 +32,7 @@ abstract contract ERC165 is IERC165 {
      *
      * Time complexity O(1), guaranteed to always use less than 30 000 gas.
      */
-    function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
+    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
         return _supportedInterfaces[interfaceId];
     }
 

+ 23 - 0
contracts/introspection/ERC165Checker.sol

@@ -40,6 +40,29 @@ library ERC165Checker {
             _supportsERC165Interface(account, interfaceId);
     }
 
+    /**
+     * @dev Returns a boolean array where each value corresponds to the
+     * interfaces passed in and whether they're supported or not. This allows
+     * you to batch check interfaces for a contract where your expectation
+     * is that some interfaces may not be supported.
+     *
+     * See {IERC165-supportsInterface}.
+     */
+    function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool[] memory) {
+        // an array of booleans corresponding to interfaceIds and whether they're supported or not
+        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
+
+        // query support of ERC165 itself
+        if (supportsERC165(account)) {
+            // query support of each interface in interfaceIds
+            for (uint256 i = 0; i < interfaceIds.length; i++) {
+                interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);
+            }
+        }
+
+        return interfaceIdsSupported;
+    }
+
     /**
      * @dev Returns true if `account` supports all the interfaces defined in
      * `interfaceIds`. Support for {IERC165} itself is queried automatically.

+ 1 - 1
contracts/introspection/ERC1820Implementer.sol

@@ -20,7 +20,7 @@ contract ERC1820Implementer is IERC1820Implementer {
     /**
      * See {IERC1820Implementer-canImplementInterfaceForAddress}.
      */
-    function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) public view override returns (bytes32) {
+    function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) public view virtual override returns (bytes32) {
         return _supportedInterfaces[interfaceHash][account] ? _ERC1820_ACCEPT_MAGIC : bytes32(0x00);
     }
 

+ 127 - 4
contracts/math/SafeMath.sol

@@ -6,6 +6,62 @@ pragma solidity ^0.8.0;
  * @dev Wrappers over Solidity's arithmetic operations.
  */
 library SafeMath {
+    /**
+     * @dev Returns the addition of two unsigned integers, with an overflow flag.
+     */
+    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        unchecked {
+            uint256 c = a + b;
+            if (c < a) return (false, 0);
+            return (true, c);
+        }
+    }
+
+    /**
+     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
+     */
+    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        unchecked {
+            if (b > a) return (false, 0);
+            return (true, a - b);
+        }
+    }
+
+    /**
+     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
+     */
+    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        unchecked {
+            // 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 (true, 0);
+            uint256 c = a * b;
+            if (c / a != b) return (false, 0);
+            return (true, c);
+        }
+    }
+
+    /**
+     * @dev Returns the division of two unsigned integers, with a division by zero flag.
+     */
+    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        unchecked {
+            if (b == 0) return (false, 0);
+            return (true, a / b);
+        }
+    }
+
+    /**
+     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
+     */
+    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        unchecked {
+            if (b == 0) return (false, 0);
+            return (true, a % b);
+        }
+    }
+
     /**
      * @dev Returns the addition of two unsigned integers, reverting on
      * overflow.
@@ -49,10 +105,10 @@ library SafeMath {
     }
 
     /**
-     * @dev Returns the integer division of two unsigned integers. Reverts on
+     * @dev Returns the integer division of two unsigned integers, reverting on
      * division by zero. The result is rounded towards zero.
      *
-     * Counterpart to Solidity's `/` operator. 
+     * Counterpart to Solidity's `/` operator.
      *
      * Requirements:
      *
@@ -64,9 +120,11 @@ library SafeMath {
 
     /**
      * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
-     * Reverts when dividing by zero.
+     * reverting when dividing by zero.
      *
-     * Counterpart to Solidity's `%` operator.
+     * Counterpart to Solidity's `%` operator. This function uses a `revert`
+     * opcode (which leaves remaining gas untouched) while Solidity uses an
+     * invalid opcode to revert (consuming all remaining gas).
      *
      * Requirements:
      *
@@ -75,4 +133,69 @@ library SafeMath {
     function mod(uint256 a, uint256 b) internal pure returns (uint256) {
         return a % b;
     }
+
+    /**
+     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
+     * overflow (when the result is negative).
+     *
+     * CAUTION: This function is deprecated because it requires allocating memory for the error
+     * message unnecessarily. For custom revert reasons use {trySub}.
+     *
+     * Counterpart to Solidity's `-` operator.
+     *
+     * Requirements:
+     *
+     * - Subtraction cannot overflow.
+     */
+    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
+        unchecked {
+            require(b <= a, errorMessage);
+            return a - b;
+        }
+    }
+
+    /**
+     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
+     * division by zero. The result is rounded towards zero.
+     *
+     * Counterpart to Solidity's `%` operator. This function uses a `revert`
+     * opcode (which leaves remaining gas untouched) while Solidity uses an
+     * invalid opcode to revert (consuming all remaining gas).
+     *
+     * 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(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
+        unchecked {
+            require(b > 0, errorMessage);
+            return a / b;
+        }
+    }
+
+    /**
+     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
+     * reverting with custom message when dividing by zero.
+     *
+     * CAUTION: This function is deprecated because it requires allocating memory for the error
+     * message unnecessarily. For custom revert reasons use {tryMod}.
+     *
+     * Counterpart to Solidity's `%` operator. This function uses a `revert`
+     * opcode (which leaves remaining gas untouched) while Solidity uses an
+     * invalid opcode to revert (consuming all remaining gas).
+     *
+     * Requirements:
+     *
+     * - The divisor cannot be zero.
+     */
+    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
+        unchecked {
+            require(b > 0, errorMessage);
+            return a % b;
+        }
+    }
 }

+ 32 - 0
contracts/mocks/ClonesMock.sol

@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity >=0.6.0 <0.9.0;
+
+import "../proxy/Clones.sol";
+import "../utils/Address.sol";
+
+contract ClonesMock {
+    using Address for address;
+    using Clones for address;
+
+    event NewInstance(address instance);
+
+    function clone(address master, bytes calldata initdata) public payable {
+        _initAndEmit(master.clone(), initdata);
+    }
+
+    function cloneDeterministic(address master, bytes32 salt, bytes calldata initdata) public payable {
+        _initAndEmit(master.cloneDeterministic(salt), initdata);
+    }
+
+    function predictDeterministicAddress(address master, bytes32 salt) public view returns (address predicted) {
+        return master.predictDeterministicAddress(salt);
+    }
+
+    function _initAndEmit(address instance, bytes memory initdata) private {
+        if (initdata.length > 0) {
+            instance.functionCallWithValue(initdata, msg.value);
+        }
+        emit NewInstance(instance);
+    }
+}

+ 1 - 1
contracts/mocks/ContextMock.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 
 contract ContextMock is Context {
     event Sender(address sender);

+ 4 - 0
contracts/mocks/ERC165CheckerMock.sol

@@ -18,4 +18,8 @@ contract ERC165CheckerMock {
     function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) public view returns (bool) {
         return account.supportsAllInterfaces(interfaceIds);
     }
+
+    function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) public view returns (bool[] memory) {
+        return account.getSupportedInterfaces(interfaceIds);
+    }
 }

+ 7 - 1
contracts/mocks/ERC777Mock.sol

@@ -2,10 +2,12 @@
 
 pragma solidity ^0.8.0;
 
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 import "../token/ERC777/ERC777.sol";
 
 contract ERC777Mock is Context, ERC777 {
+    event BeforeTokenTransfer();
+
     constructor(
         address initialHolder,
         uint256 initialBalance,
@@ -28,4 +30,8 @@ contract ERC777Mock is Context, ERC777 {
     function approveInternal(address holder, address spender, uint256 value) public {
         _approve(holder, spender, value);
     }
+
+    function _beforeTokenTransfer(address, address, address, uint256) internal override {
+        emit BeforeTokenTransfer();
+    }
 }

+ 4 - 1
contracts/mocks/ERC777SenderRecipientMock.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 import "../token/ERC777/IERC777.sol";
 import "../token/ERC777/IERC777Sender.sol";
 import "../token/ERC777/IERC777Recipient.sol";
@@ -34,6 +34,9 @@ contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient,
         uint256 toBalance
     );
 
+    // Emitted in ERC777Mock. Here for easier decoding
+    event BeforeTokenTransfer();
+
     bool private _shouldRevertSend;
     bool private _shouldRevertReceive;
 

+ 8 - 0
contracts/mocks/EnumerableMapMock.sol

@@ -34,7 +34,15 @@ contract EnumerableMapMock {
     }
 
 
+    function tryGet(uint256 key) public view returns (bool, address) {
+        return _map.tryGet(key);
+    }
+
     function get(uint256 key) public view returns (address) {
         return _map.get(key);
     }
+
+    function getWithMessage(uint256 key, string calldata errorMessage) public view returns (address) {
+        return _map.get(key, errorMessage);
+    }
 }

+ 1 - 1
contracts/mocks/GSNRecipientMock.sol

@@ -13,7 +13,7 @@ contract GSNRecipientMock is ContextMock, GSNRecipient {
 
     function acceptRelayedCall(address, address, bytes calldata, uint256, uint256, uint256, uint256, bytes calldata, uint256)
         external
-        view
+        pure
         override
         returns (uint256, bytes memory)
     {

+ 1 - 1
contracts/mocks/ReentrancyAttack.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 contract ReentrancyAttack is Context {
     function callSender(bytes4 data) public {
         // solhint-disable-next-line avoid-low-level-calls

+ 1 - 1
contracts/mocks/SafeERC20Helper.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 import "../token/ERC20/IERC20.sol";
 import "../token/ERC20/SafeERC20.sol";
 

+ 84 - 6
contracts/mocks/SafeMathMock.sol

@@ -5,23 +5,101 @@ pragma solidity ^0.8.0;
 import "../math/SafeMath.sol";
 
 contract SafeMathMock {
-    function mul(uint256 a, uint256 b) public pure returns (uint256) {
-        return SafeMath.mul(a, b);
+    function tryAdd(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
+        return SafeMath.tryAdd(a, b);
     }
 
-    function div(uint256 a, uint256 b) public pure returns (uint256) {
-        return SafeMath.div(a, b);
+    function trySub(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
+        return SafeMath.trySub(a, b);
     }
 
-    function sub(uint256 a, uint256 b) public pure returns (uint256) {
-        return SafeMath.sub(a, b);
+    function tryMul(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
+        return SafeMath.tryMul(a, b);
+    }
+
+    function tryDiv(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
+        return SafeMath.tryDiv(a, b);
+    }
+
+    function tryMod(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) {
+        return SafeMath.tryMod(a, b);
     }
 
     function add(uint256 a, uint256 b) public pure returns (uint256) {
         return SafeMath.add(a, b);
     }
 
+    function sub(uint256 a, uint256 b) public pure returns (uint256) {
+        return SafeMath.sub(a, b);
+    }
+
+    function mul(uint256 a, uint256 b) public pure returns (uint256) {
+        return SafeMath.mul(a, b);
+    }
+
+    function div(uint256 a, uint256 b) public pure returns (uint256) {
+        return SafeMath.div(a, b);
+    }
+
     function mod(uint256 a, uint256 b) public pure returns (uint256) {
         return SafeMath.mod(a, b);
     }
+
+    function subWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
+        return SafeMath.sub(a, b, errorMessage);
+    }
+
+    function divWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
+        return SafeMath.div(a, b, errorMessage);
+    }
+
+    function modWithMessage(uint256 a, uint256 b, string memory errorMessage) public pure returns (uint256) {
+        return SafeMath.mod(a, b, errorMessage);
+    }
+
+    function addMemoryCheck() public pure returns (uint256 mem) {
+        uint256 length = 32;
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := mload(0x40) }
+        for (uint256 i = 0; i < length; ++i) { SafeMath.add(1, 1); }
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := sub(mload(0x40), mem) }
+    }
+
+    function subMemoryCheck() public pure returns (uint256 mem) {
+        uint256 length = 32;
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := mload(0x40) }
+        for (uint256 i = 0; i < length; ++i) { SafeMath.sub(1, 1); }
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := sub(mload(0x40), mem) }
+    }
+
+    function mulMemoryCheck() public pure returns (uint256 mem) {
+        uint256 length = 32;
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := mload(0x40) }
+        for (uint256 i = 0; i < length; ++i) { SafeMath.mul(1, 1); }
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := sub(mload(0x40), mem) }
+    }
+
+    function divMemoryCheck() public pure returns (uint256 mem) {
+        uint256 length = 32;
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := mload(0x40) }
+        for (uint256 i = 0; i < length; ++i) { SafeMath.div(1, 1); }
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := sub(mload(0x40), mem) }
+    }
+
+    function modMemoryCheck() public pure returns (uint256 mem) {
+        uint256 length = 32;
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := mload(0x40) }
+        for (uint256 i = 0; i < length; ++i) { SafeMath.mod(1, 1); }
+        // solhint-disable-next-line no-inline-assembly
+        assembly { mem := sub(mload(0x40), mem) }
+    }
+
 }

+ 1 - 1
contracts/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@openzeppelin/contracts",
   "description": "Secure Smart Contract library for Solidity",
-  "version": "3.3.0",
+  "version": "3.3.0-solc-0.8",
   "files": [
     "**/*.sol",
     "/build/contracts/*.json",

+ 4 - 2
contracts/payment/PaymentSplitter.sol

@@ -2,7 +2,9 @@
 
 pragma solidity ^0.8.0;
 
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
+import "../math/SafeMath.sol";
+import "../utils/Address.sol";
 
 /**
  * @title PaymentSplitter
@@ -109,7 +111,7 @@ contract PaymentSplitter is Context {
         _released[account] = _released[account] + payment;
         _totalReleased = _totalReleased + payment;
 
-        account.transfer(payment);
+        Address.sendValue(account, payment);
         emit PaymentReleased(account, payment);
     }
 

+ 1 - 1
contracts/payment/escrow/Escrow.sol

@@ -34,7 +34,7 @@ contract Escrow is Ownable {
      * @dev Stores the sent amount as credit to be withdrawn.
      * @param payee The destination address of the funds.
      */
-    function deposit(address payee) public virtual payable onlyOwner {
+    function deposit(address payee) public payable virtual onlyOwner {
         uint256 amount = msg.value;
         _deposits[payee] = _deposits[payee] + amount;
 

+ 11 - 9
contracts/payment/escrow/RefundEscrow.sol

@@ -15,6 +15,8 @@ import "./ConditionalEscrow.sol";
  * with `RefundEscrow` will be made through the owner contract.
  */
 contract RefundEscrow is ConditionalEscrow {
+    using Address for address payable;
+
     enum State { Active, Refunding, Closed }
 
     event RefundsClosed();
@@ -36,14 +38,14 @@ contract RefundEscrow is ConditionalEscrow {
     /**
      * @return The current state of the escrow.
      */
-    function state() public view returns (State) {
+    function state() public view virtual returns (State) {
         return _state;
     }
 
     /**
      * @return The beneficiary of the escrow.
      */
-    function beneficiary() public view returns (address) {
+    function beneficiary() public view virtual returns (address payable) {
         return _beneficiary;
     }
 
@@ -52,7 +54,7 @@ contract RefundEscrow is ConditionalEscrow {
      * @param refundee The address funds will be sent to if a refund occurs.
      */
     function deposit(address refundee) public payable virtual override {
-        require(_state == State.Active, "RefundEscrow: can only deposit while active");
+        require(state() == State.Active, "RefundEscrow: can only deposit while active");
         super.deposit(refundee);
     }
 
@@ -60,8 +62,8 @@ contract RefundEscrow is ConditionalEscrow {
      * @dev Allows for the beneficiary to withdraw their funds, rejecting
      * further deposits.
      */
-    function close() public onlyOwner virtual {
-        require(_state == State.Active, "RefundEscrow: can only close while active");
+    function close() public virtual onlyOwner {
+        require(state() == State.Active, "RefundEscrow: can only close while active");
         _state = State.Closed;
         emit RefundsClosed();
     }
@@ -70,7 +72,7 @@ contract RefundEscrow is ConditionalEscrow {
      * @dev Allows for refunds to take place, rejecting further deposits.
      */
     function enableRefunds() public onlyOwner virtual {
-        require(_state == State.Active, "RefundEscrow: can only enable refunds while active");
+        require(state() == State.Active, "RefundEscrow: can only enable refunds while active");
         _state = State.Refunding;
         emit RefundsEnabled();
     }
@@ -79,8 +81,8 @@ contract RefundEscrow is ConditionalEscrow {
      * @dev Withdraws the beneficiary's funds.
      */
     function beneficiaryWithdraw() public virtual {
-        require(_state == State.Closed, "RefundEscrow: beneficiary can only withdraw while closed");
-        _beneficiary.transfer(address(this).balance);
+        require(state() == State.Closed, "RefundEscrow: beneficiary can only withdraw while closed");
+        beneficiary().sendValue(address(this).balance);
     }
 
     /**
@@ -88,6 +90,6 @@ contract RefundEscrow is ConditionalEscrow {
      * 'payee' argument, but we ignore it here since the condition is global, not per-payee.
      */
     function withdrawalAllowed(address) public view override returns (bool) {
-        return _state == State.Refunding;
+        return state() == State.Refunding;
     }
 }

+ 1 - 1
contracts/presets/ERC1155PresetMinterPauser.sol

@@ -3,7 +3,7 @@
 pragma solidity ^0.8.0;
 
 import "../access/AccessControl.sol";
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 import "../token/ERC1155/ERC1155.sol";
 import "../token/ERC1155/ERC1155Burnable.sol";
 import "../token/ERC1155/ERC1155Pausable.sol";

+ 1 - 1
contracts/presets/ERC20PresetFixedSupply.sol

@@ -15,7 +15,7 @@ import "../token/ERC20/ERC20Burnable.sol";
  */
 contract ERC20PresetFixedSupply is ERC20Burnable {
     /**
-     * @dev Mints `initialSupply` amount of token and transfers them to `owner`.  
+     * @dev Mints `initialSupply` amount of token and transfers them to `owner`.
      *
      * See {ERC20-constructor}.
      */

+ 1 - 1
contracts/presets/ERC20PresetMinterPauser.sol

@@ -3,7 +3,7 @@
 pragma solidity ^0.8.0;
 
 import "../access/AccessControl.sol";
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 import "../token/ERC20/ERC20.sol";
 import "../token/ERC20/ERC20Burnable.sol";
 import "../token/ERC20/ERC20Pausable.sol";

+ 1 - 1
contracts/presets/ERC721PresetMinterPauserAutoId.sol

@@ -3,7 +3,7 @@
 pragma solidity ^0.8.0;
 
 import "../access/AccessControl.sol";
-import "../GSN/Context.sol";
+import "../utils/Context.sol";
 import "../utils/Counters.sol";
 import "../token/ERC721/ERC721.sol";
 import "../token/ERC721/ERC721Burnable.sol";

+ 1 - 1
contracts/presets/ERC777PresetFixedSupply.sol

@@ -11,7 +11,7 @@ import "../token/ERC777/ERC777.sol";
  */
 contract ERC777PresetFixedSupply is ERC777 {
     /**
-     * @dev Mints `initialSupply` amount of token and transfers them to `owner`.  
+     * @dev Mints `initialSupply` amount of token and transfers them to `owner`.
      *
      * See {ERC777-constructor}.
      */

+ 4 - 4
contracts/proxy/BeaconProxy.sol

@@ -38,7 +38,7 @@ contract BeaconProxy is Proxy {
     /**
      * @dev Returns the current beacon address.
      */
-    function _beacon() internal view returns (address beacon) {
+    function _beacon() internal view virtual returns (address beacon) {
         bytes32 slot = _BEACON_SLOT;
         // solhint-disable-next-line no-inline-assembly
         assembly {
@@ -49,21 +49,21 @@ contract BeaconProxy is Proxy {
     /**
      * @dev Returns the current implementation address of the associated beacon.
      */
-    function _implementation() internal view override returns (address) {
+    function _implementation() internal view virtual override returns (address) {
         return IBeacon(_beacon()).implementation();
     }
 
     /**
      * @dev Changes the proxy to use a new beacon.
      *
-     * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. 
+     * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
      *
      * Requirements:
      *
      * - `beacon` must be a contract.
      * - The implementation returned by `beacon` must be a contract.
      */
-    function _setBeacon(address beacon, bytes memory data) internal {
+    function _setBeacon(address beacon, bytes memory data) internal virtual {
         require(
             Address.isContract(beacon),
             "BeaconProxy: beacon is not a contract"

+ 76 - 0
contracts/proxy/Clones.sol

@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity >=0.6.0 <0.9.0;
+
+/**
+ * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
+ * deploying minimal proxy contracts, also known as "clones".
+ *
+ * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
+ * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
+ *
+ * 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.
+ */
+library Clones {
+    /**
+     * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
+     *
+     * This function uses the create opcode, which should never revert.
+     */
+    function clone(address master) 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, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
+            instance := create(0, ptr, 0x37)
+        }
+        require(instance != address(0), "ERC1167: create failed");
+    }
+
+    /**
+     * @dev Deploys and returns the address of a clone that mimics the behaviour of `master`.
+     *
+     * 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 clones cannot be deployed twice at the same address.
+     */
+    function cloneDeterministic(address master, 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, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
+            instance := create2(0, ptr, 0x37, salt)
+        }
+        require(instance != address(0), "ERC1167: create2 failed");
+    }
+
+    /**
+     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
+     */
+    function predictDeterministicAddress(address master, 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, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
+            mstore(add(ptr, 0x38), shl(0x60, deployer))
+            mstore(add(ptr, 0x4c), salt)
+            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
+            predicted := keccak256(add(ptr, 0x37), 0x55)
+        }
+    }
+
+    /**
+     * @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));
+    }
+}

+ 4 - 12
contracts/proxy/Initializable.sol

@@ -3,16 +3,17 @@
 // solhint-disable-next-line compiler-version
 pragma solidity ^0.8.0;
 
+import "../utils/Address.sol";
 
 /**
  * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
  * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
  * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
  * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
- * 
+ *
  * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
  * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
- * 
+ *
  * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
  * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
  */
@@ -49,15 +50,6 @@ abstract contract Initializable {
 
     /// @dev Returns true if and only if the function is running in the constructor
     function _isConstructor() private view returns (bool) {
-        // extcodesize checks the size of the code stored in an address, and
-        // address returns the current address. Since the code is still not
-        // deployed when running a constructor, any checks on its code size will
-        // yield zero, making it an effective way to detect if a contract is
-        // under construction or not.
-        address self = address(this);
-        uint256 cs;
-        // solhint-disable-next-line no-inline-assembly
-        assembly { cs := extcodesize(self) }
-        return cs == 0;
+        return !Address.isContract(address(this));
     }
 }

+ 10 - 10
contracts/proxy/Proxy.sol

@@ -6,19 +6,19 @@ pragma solidity ^0.8.0;
  * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
  * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
  * be specified by overriding the virtual {_implementation} function.
- * 
+ *
  * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
  * different contract through the {_delegate} function.
- * 
+ *
  * The success and return data of the delegated call will be returned back to the caller of the proxy.
  */
 abstract contract Proxy {
     /**
      * @dev Delegates the current call to `implementation`.
-     * 
+     *
      * This function does not return to its internall call site, it will return directly to the external caller.
      */
-    function _delegate(address implementation) internal {
+    function _delegate(address implementation) internal virtual {
         // solhint-disable-next-line no-inline-assembly
         assembly {
             // Copy msg.data. We take full control of memory in this inline assembly
@@ -44,14 +44,14 @@ abstract contract Proxy {
      * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
      * and {_fallback} should delegate.
      */
-    function _implementation() internal virtual view returns (address);
+    function _implementation() internal view virtual returns (address);
 
     /**
      * @dev Delegates the current call to the address returned by `_implementation()`.
-     * 
+     *
      * This function does not return to its internall call site, it will return directly to the external caller.
      */
-    function _fallback() internal {
+    function _fallback() internal virtual {
         _beforeFallback();
         _delegate(_implementation());
     }
@@ -60,7 +60,7 @@ abstract contract Proxy {
      * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
      * function in the contract matches the call data.
      */
-    fallback () external payable {
+    fallback () external payable virtual {
         _fallback();
     }
 
@@ -68,14 +68,14 @@ abstract contract Proxy {
      * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
      * is empty.
      */
-    receive () external payable {
+    receive () external payable virtual {
         _fallback();
     }
 
     /**
      * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
      * call, or as part of the Solidity `fallback` or `receive` functions.
-     * 
+     *
      * If overriden should call `super._beforeFallback()`.
      */
     function _beforeFallback() internal virtual {

+ 15 - 15
contracts/proxy/ProxyAdmin.sol

@@ -13,12 +13,12 @@ contract ProxyAdmin is Ownable {
 
     /**
      * @dev Returns the current implementation of `proxy`.
-     * 
+     *
      * Requirements:
-     * 
+     *
      * - This contract must be the admin of `proxy`.
      */
-    function getProxyImplementation(TransparentUpgradeableProxy proxy) public view returns (address) {
+    function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
         // We need to manually run the static call since the getter cannot be flagged as view
         // bytes4(keccak256("implementation()")) == 0x5c60da1b
         (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
@@ -28,12 +28,12 @@ contract ProxyAdmin is Ownable {
 
     /**
      * @dev Returns the current admin of `proxy`.
-     * 
+     *
      * Requirements:
-     * 
+     *
      * - This contract must be the admin of `proxy`.
      */
-    function getProxyAdmin(TransparentUpgradeableProxy proxy) public view returns (address) {
+    function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
         // We need to manually run the static call since the getter cannot be flagged as view
         // bytes4(keccak256("admin()")) == 0xf851a440
         (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
@@ -43,35 +43,35 @@ contract ProxyAdmin is Ownable {
 
     /**
      * @dev Changes the admin of `proxy` to `newAdmin`.
-     * 
+     *
      * Requirements:
-     * 
+     *
      * - This contract must be the current admin of `proxy`.
      */
-    function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public onlyOwner {
+    function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
         proxy.changeAdmin(newAdmin);
     }
 
     /**
      * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
-     * 
+     *
      * Requirements:
-     * 
+     *
      * - This contract must be the admin of `proxy`.
      */
-    function upgrade(TransparentUpgradeableProxy proxy, address implementation) public onlyOwner {
+    function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
         proxy.upgradeTo(implementation);
     }
 
     /**
      * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
      * {TransparentUpgradeableProxy-upgradeToAndCall}.
-     * 
+     *
      * Requirements:
-     * 
+     *
      * - This contract must be the admin of `proxy`.
      */
-    function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable onlyOwner {
+    function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
         proxy.upgradeToAndCall{value: msg.value}(implementation, data);
     }
 }

+ 9 - 3
contracts/proxy/README.adoc

@@ -3,13 +3,15 @@
 [.readme-notice]
 NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/proxy
 
-This is a low-level set of contracts implementing the proxy pattern for upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page.
+This is a low-level set of contracts implementing different proxy patterns with and without upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page.
 
 The abstract {Proxy} contract implements the core delegation functionality. If the concrete proxies that we provide below are not suitable, we encourage building on top of this base contract since it contains an assembly block that may be hard to get right.
 
 Upgradeability is implemented in the {UpgradeableProxy} contract, although it provides only an internal upgrade interface. For an upgrade interface exposed externally to an admin, we provide {TransparentUpgradeableProxy}. Both of these contracts use the storage slots specified in https://eips.ethereum.org/EIPS/eip-1967[EIP1967] to avoid clashes with the storage of the implementation contract behind the proxy.
 
-An alternative upgradeability mechanism is provided in <<UpgradeableBeacon>>. 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.
+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.
 
@@ -21,7 +23,7 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th
 
 {{TransparentUpgradeableProxy}}
 
-== UpgradeableBeacon
+== Beacon
 
 {{BeaconProxy}}
 
@@ -29,6 +31,10 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th
 
 {{UpgradeableBeacon}}
 
+== Minimal Clones
+
+{{Clones}}
+
 == Utilities
 
 {{Initializable}}

+ 18 - 20
contracts/proxy/TransparentUpgradeableProxy.sol

@@ -6,22 +6,22 @@ import "./UpgradeableProxy.sol";
 
 /**
  * @dev This contract implements a proxy that is upgradeable by an admin.
- * 
+ *
  * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
  * clashing], which can potentially be used in an attack, this contract uses the
  * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
  * things that go hand in hand:
- * 
+ *
  * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
  * that call matches one of the admin functions exposed by the proxy itself.
  * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
  * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
  * "admin cannot fallback to proxy target".
- * 
+ *
  * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
  * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
  * to sudden errors when trying to call a function from the proxy implementation.
- * 
+ *
  * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
  * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
  */
@@ -60,9 +60,9 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
 
     /**
      * @dev Returns the current admin.
-     * 
+     *
      * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
-     * 
+     *
      * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
      * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
      * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
@@ -73,9 +73,9 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
 
     /**
      * @dev Returns the current implementation.
-     * 
+     *
      * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
-     * 
+     *
      * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
      * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
      * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
@@ -86,12 +86,12 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
 
     /**
      * @dev Changes the admin of the proxy.
-     * 
+     *
      * Emits an {AdminChanged} event.
-     * 
+     *
      * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
      */
-    function changeAdmin(address newAdmin) external ifAdmin {
+    function changeAdmin(address newAdmin) external virtual ifAdmin {
         require(newAdmin != address(0), "TransparentUpgradeableProxy: new admin is the zero address");
         emit AdminChanged(_admin(), newAdmin);
         _setAdmin(newAdmin);
@@ -99,10 +99,10 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
 
     /**
      * @dev Upgrade the implementation of the proxy.
-     * 
+     *
      * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
      */
-    function upgradeTo(address newImplementation) external ifAdmin {
+    function upgradeTo(address newImplementation) external virtual ifAdmin {
         _upgradeTo(newImplementation);
     }
 
@@ -110,20 +110,18 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
      * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
      * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
      * proxied contract.
-     * 
+     *
      * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
      */
-    function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
+    function upgradeToAndCall(address newImplementation, bytes calldata data) external payable virtual ifAdmin {
         _upgradeTo(newImplementation);
-        // solhint-disable-next-line avoid-low-level-calls
-        (bool success,) = newImplementation.delegatecall(data);
-        require(success);
+        Address.functionDelegateCall(newImplementation, data);
     }
 
     /**
      * @dev Returns the current admin.
      */
-    function _admin() internal view returns (address adm) {
+    function _admin() internal view virtual returns (address adm) {
         bytes32 slot = _ADMIN_SLOT;
         // solhint-disable-next-line no-inline-assembly
         assembly {
@@ -146,7 +144,7 @@ contract TransparentUpgradeableProxy is UpgradeableProxy {
     /**
      * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
      */
-    function _beforeFallback() internal override virtual {
+    function _beforeFallback() internal virtual override {
         require(msg.sender != _admin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
         super._beforeFallback();
     }

+ 2 - 2
contracts/proxy/UpgradeableBeacon.sol

@@ -31,7 +31,7 @@ contract UpgradeableBeacon is IBeacon, Ownable {
     /**
      * @dev Returns the current implementation address.
      */
-    function implementation() public view override returns (address) {
+    function implementation() public view virtual override returns (address) {
         return _implementation;
     }
 
@@ -45,7 +45,7 @@ contract UpgradeableBeacon is IBeacon, Ownable {
      * - msg.sender must be the owner of the contract.
      * - `newImplementation` must be a contract.
      */
-    function upgradeTo(address newImplementation) public onlyOwner {
+    function upgradeTo(address newImplementation) public virtual onlyOwner {
         _setImplementation(newImplementation);
         emit Upgraded(newImplementation);
     }

+ 6 - 8
contracts/proxy/UpgradeableProxy.sol

@@ -10,14 +10,14 @@ import "../utils/Address.sol";
  * implementation address that can be changed. This address is stored in storage in the location specified by
  * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
  * implementation behind the proxy.
- * 
+ *
  * Upgradeability is only provided internally through {_upgradeTo}. For an externally upgradeable proxy see
  * {TransparentUpgradeableProxy}.
  */
 contract UpgradeableProxy is Proxy {
     /**
      * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
-     * 
+     *
      * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
      * function call, and allows initializating the storage of the proxy like a Solidity constructor.
      */
@@ -25,9 +25,7 @@ contract UpgradeableProxy is Proxy {
         assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
         _setImplementation(_logic);
         if(_data.length > 0) {
-            // solhint-disable-next-line avoid-low-level-calls
-            (bool success,) = _logic.delegatecall(_data);
-            require(success);
+            Address.functionDelegateCall(_logic, _data);
         }
     }
 
@@ -46,7 +44,7 @@ contract UpgradeableProxy is Proxy {
     /**
      * @dev Returns the current implementation address.
      */
-    function _implementation() internal override view returns (address impl) {
+    function _implementation() internal view virtual override returns (address impl) {
         bytes32 slot = _IMPLEMENTATION_SLOT;
         // solhint-disable-next-line no-inline-assembly
         assembly {
@@ -56,10 +54,10 @@ contract UpgradeableProxy is Proxy {
 
     /**
      * @dev Upgrades the proxy to a new implementation.
-     * 
+     *
      * Emits an {Upgraded} event.
      */
-    function _upgradeTo(address newImplementation) internal {
+    function _upgradeTo(address newImplementation) internal virtual {
         _setImplementation(newImplementation);
         emit Upgraded(newImplementation);
     }

+ 8 - 7
contracts/token/ERC1155/ERC1155.sol

@@ -5,7 +5,7 @@ pragma solidity ^0.8.0;
 import "./IERC1155.sol";
 import "./IERC1155MetadataURI.sol";
 import "./IERC1155Receiver.sol";
-import "../../GSN/Context.sol";
+import "../../utils/Context.sol";
 import "../../introspection/ERC165.sol";
 import "../../utils/Address.sol";
 
@@ -70,7 +70,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
      * Clients calling this function must replace the `\{id\}` substring with the
      * actual token type ID.
      */
-    function uri(uint256) external view override returns (string memory) {
+    function uri(uint256) external view virtual override returns (string memory) {
         return _uri;
     }
 
@@ -81,7 +81,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
      *
      * - `account` cannot be the zero address.
      */
-    function balanceOf(address account, uint256 id) public view override returns (uint256) {
+    function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
         require(account != address(0), "ERC1155: balance query for the zero address");
         return _balances[id][account];
     }
@@ -99,6 +99,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
     )
         public
         view
+        virtual
         override
         returns (uint256[] memory)
     {
@@ -107,8 +108,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
         uint256[] memory batchBalances = new uint256[](accounts.length);
 
         for (uint256 i = 0; i < accounts.length; ++i) {
-            require(accounts[i] != address(0), "ERC1155: batch balance query for the zero address");
-            batchBalances[i] = _balances[ids[i]][accounts[i]];
+            batchBalances[i] = balanceOf(accounts[i], ids[i]);
         }
 
         return batchBalances;
@@ -127,7 +127,7 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
     /**
      * @dev See {IERC1155-isApprovedForAll}.
      */
-    function isApprovedForAll(address account, address operator) public view override returns (bool) {
+    function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
         return _operatorApprovals[account][operator];
     }
 
@@ -344,7 +344,8 @@ contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
         uint256[] memory amounts,
         bytes memory data
     )
-        internal virtual
+        internal
+        virtual
     { }
 
     function _doSafeTransferAcceptanceCheck(

+ 3 - 1
contracts/token/ERC1155/ERC1155Pausable.sol

@@ -30,7 +30,9 @@ abstract contract ERC1155Pausable is ERC1155, Pausable {
         uint256[] memory amounts,
         bytes memory data
     )
-        internal virtual override
+        internal
+        virtual
+        override
     {
         super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
 

+ 7 - 7
contracts/token/ERC20/ERC20.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../../GSN/Context.sol";
+import "../../utils/Context.sol";
 import "./IERC20.sol";
 
 /**
@@ -58,7 +58,7 @@ contract ERC20 is Context, IERC20 {
     /**
      * @dev Returns the name of the token.
      */
-    function name() public view returns (string memory) {
+    function name() public view virtual returns (string memory) {
         return _name;
     }
 
@@ -66,7 +66,7 @@ contract ERC20 is Context, IERC20 {
      * @dev Returns the symbol of the token, usually a shorter version of the
      * name.
      */
-    function symbol() public view returns (string memory) {
+    function symbol() public view virtual returns (string memory) {
         return _symbol;
     }
 
@@ -83,21 +83,21 @@ contract ERC20 is Context, IERC20 {
      * no way affects any of the arithmetic of the contract, including
      * {IERC20-balanceOf} and {IERC20-transfer}.
      */
-    function decimals() public view returns (uint8) {
+    function decimals() public view virtual returns (uint8) {
         return _decimals;
     }
 
     /**
      * @dev See {IERC20-totalSupply}.
      */
-    function totalSupply() public view override returns (uint256) {
+    function totalSupply() public view virtual override returns (uint256) {
         return _totalSupply;
     }
 
     /**
      * @dev See {IERC20-balanceOf}.
      */
-    function balanceOf(address account) public view override returns (uint256) {
+    function balanceOf(address account) public view virtual override returns (uint256) {
         return _balances[account];
     }
 
@@ -281,7 +281,7 @@ contract ERC20 is Context, IERC20 {
      * applications that interact with token contracts will not expect
      * {decimals} to ever change, and may work incorrectly if it does.
      */
-    function _setupDecimals(uint8 decimals_) internal {
+    function _setupDecimals(uint8 decimals_) internal virtual {
         _decimals = decimals_;
     }
 

+ 1 - 1
contracts/token/ERC20/ERC20Burnable.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../../GSN/Context.sol";
+import "../../utils/Context.sol";
 import "./ERC20.sol";
 
 /**

+ 1 - 1
contracts/token/ERC20/ERC20Capped.sol

@@ -22,7 +22,7 @@ abstract contract ERC20Capped is ERC20 {
     /**
      * @dev Returns the cap on the token's total supply.
      */
-    function cap() public view returns (uint256) {
+    function cap() public view virtual returns (uint256) {
         return _cap;
     }
 

+ 2 - 2
contracts/token/ERC20/ERC20Snapshot.sol

@@ -87,7 +87,7 @@ abstract contract ERC20Snapshot is ERC20 {
     /**
      * @dev Retrieves the balance of `account` at the time `snapshotId` was created.
      */
-    function balanceOfAt(address account, uint256 snapshotId) public view returns (uint256) {
+    function balanceOfAt(address account, uint256 snapshotId) public view virtual returns (uint256) {
         (bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]);
 
         return snapshotted ? value : balanceOf(account);
@@ -96,7 +96,7 @@ abstract contract ERC20Snapshot is ERC20 {
     /**
      * @dev Retrieves the total supply at the time `snapshotId` was created.
      */
-    function totalSupplyAt(uint256 snapshotId) public view returns(uint256) {
+    function totalSupplyAt(uint256 snapshotId) public view virtual returns(uint256) {
         (bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnapshots);
 
         return snapshotted ? value : totalSupply();

+ 6 - 6
contracts/token/ERC20/TokenTimelock.sol

@@ -34,21 +34,21 @@ contract TokenTimelock {
     /**
      * @return the token being held.
      */
-    function token() public view returns (IERC20) {
+    function token() public view virtual returns (IERC20) {
         return _token;
     }
 
     /**
      * @return the beneficiary of the tokens.
      */
-    function beneficiary() public view returns (address) {
+    function beneficiary() public view virtual returns (address) {
         return _beneficiary;
     }
 
     /**
      * @return the time when the tokens are released.
      */
-    function releaseTime() public view returns (uint256) {
+    function releaseTime() public view virtual returns (uint256) {
         return _releaseTime;
     }
 
@@ -57,11 +57,11 @@ contract TokenTimelock {
      */
     function release() public virtual {
         // solhint-disable-next-line not-rely-on-time
-        require(block.timestamp >= _releaseTime, "TokenTimelock: current time is before release time");
+        require(block.timestamp >= releaseTime(), "TokenTimelock: current time is before release time");
 
-        uint256 amount = _token.balanceOf(address(this));
+        uint256 amount = token().balanceOf(address(this));
         require(amount > 0, "TokenTimelock: no tokens to release");
 
-        _token.safeTransfer(_beneficiary, amount);
+        token().safeTransfer(beneficiary(), amount);
     }
 }

+ 25 - 25
contracts/token/ERC721/ERC721.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../../GSN/Context.sol";
+import "../../utils/Context.sol";
 import "./IERC721.sol";
 import "./IERC721Metadata.sol";
 import "./IERC721Enumerable.sol";
@@ -101,51 +101,51 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
     /**
      * @dev See {IERC721-balanceOf}.
      */
-    function balanceOf(address owner) public view override returns (uint256) {
+    function balanceOf(address owner) public view virtual override returns (uint256) {
         require(owner != address(0), "ERC721: balance query for the zero address");
-
         return _holderTokens[owner].length();
     }
 
     /**
      * @dev See {IERC721-ownerOf}.
      */
-    function ownerOf(uint256 tokenId) public view override returns (address) {
+    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
         return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
     }
 
     /**
      * @dev See {IERC721Metadata-name}.
      */
-    function name() public view override returns (string memory) {
+    function name() public view virtual override returns (string memory) {
         return _name;
     }
 
     /**
      * @dev See {IERC721Metadata-symbol}.
      */
-    function symbol() public view override returns (string memory) {
+    function symbol() public view virtual override returns (string memory) {
         return _symbol;
     }
 
     /**
      * @dev See {IERC721Metadata-tokenURI}.
      */
-    function tokenURI(uint256 tokenId) public view override returns (string memory) {
+    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
         require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
 
         string memory _tokenURI = _tokenURIs[tokenId];
+        string memory base = baseURI();
 
         // If there is no base URI, return the token URI.
-        if (bytes(_baseURI).length == 0) {
+        if (bytes(base).length == 0) {
             return _tokenURI;
         }
         // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
         if (bytes(_tokenURI).length > 0) {
-            return string(abi.encodePacked(_baseURI, _tokenURI));
+            return string(abi.encodePacked(base, _tokenURI));
         }
         // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
-        return string(abi.encodePacked(_baseURI, tokenId.toString()));
+        return string(abi.encodePacked(base, tokenId.toString()));
     }
 
     /**
@@ -153,21 +153,21 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
     * automatically added as a prefix in {tokenURI} to each token's URI, or
     * to the token ID if no specific URI is set for that token ID.
     */
-    function baseURI() public view returns (string memory) {
+    function baseURI() public view virtual returns (string memory) {
         return _baseURI;
     }
 
     /**
      * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
      */
-    function tokenOfOwnerByIndex(address owner, uint256 index) public view override returns (uint256) {
+    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
         return _holderTokens[owner].at(index);
     }
 
     /**
      * @dev See {IERC721Enumerable-totalSupply}.
      */
-    function totalSupply() public view override returns (uint256) {
+    function totalSupply() public view virtual override returns (uint256) {
         // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
         return _tokenOwners.length();
     }
@@ -175,7 +175,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
     /**
      * @dev See {IERC721Enumerable-tokenByIndex}.
      */
-    function tokenByIndex(uint256 index) public view override returns (uint256) {
+    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
         (uint256 tokenId, ) = _tokenOwners.at(index);
         return tokenId;
     }
@@ -184,10 +184,10 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
      * @dev See {IERC721-approve}.
      */
     function approve(address to, uint256 tokenId) public virtual override {
-        address owner = ownerOf(tokenId);
+        address owner = ERC721.ownerOf(tokenId);
         require(to != owner, "ERC721: approval to current owner");
 
-        require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
+        require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()),
             "ERC721: approve caller is not owner nor approved for all"
         );
 
@@ -197,7 +197,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
     /**
      * @dev See {IERC721-getApproved}.
      */
-    function getApproved(uint256 tokenId) public view override returns (address) {
+    function getApproved(uint256 tokenId) public view virtual override returns (address) {
         require(_exists(tokenId), "ERC721: approved query for nonexistent token");
 
         return _tokenApprovals[tokenId];
@@ -216,7 +216,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
     /**
      * @dev See {IERC721-isApprovedForAll}.
      */
-    function isApprovedForAll(address owner, address operator) public view override returns (bool) {
+    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
         return _operatorApprovals[owner][operator];
     }
 
@@ -276,7 +276,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
      * Tokens start existing when they are minted (`_mint`),
      * and stop existing when they are burned (`_burn`).
      */
-    function _exists(uint256 tokenId) internal view returns (bool) {
+    function _exists(uint256 tokenId) internal view virtual returns (bool) {
         return _tokenOwners.contains(tokenId);
     }
 
@@ -287,10 +287,10 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
      *
      * - `tokenId` must exist.
      */
-    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
+    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
         require(_exists(tokenId), "ERC721: operator query for nonexistent token");
-        address owner = ownerOf(tokenId);
-        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
+        address owner = ERC721.ownerOf(tokenId);
+        return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender));
     }
 
     /**
@@ -352,7 +352,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
      * Emits a {Transfer} event.
      */
     function _burn(uint256 tokenId) internal virtual {
-        address owner = ownerOf(tokenId);
+        address owner = ERC721.ownerOf(tokenId); // internal owner
 
         _beforeTokenTransfer(owner, address(0), tokenId);
 
@@ -383,7 +383,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
      * Emits a {Transfer} event.
      */
     function _transfer(address from, address to, uint256 tokenId) internal virtual {
-        require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
+        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner
         require(to != address(0), "ERC721: transfer to the zero address");
 
         _beforeTokenTransfer(from, to, tokenId);
@@ -449,7 +449,7 @@ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable
 
     function _approve(address to, uint256 tokenId) private {
         _tokenApprovals[tokenId] = to;
-        emit Approval(ownerOf(tokenId), to, tokenId);
+        emit Approval(ERC721.ownerOf(tokenId), to, tokenId); // internal owner
     }
 
     /**

+ 1 - 1
contracts/token/ERC721/ERC721Burnable.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../../GSN/Context.sol";
+import "../../utils/Context.sol";
 import "./ERC721.sol";
 
 /**

+ 2 - 2
contracts/token/ERC721/IERC721.sol

@@ -117,8 +117,8 @@ interface IERC721 is IERC165 {
       *
       * Requirements:
       *
-     * - `from` cannot be the zero address.
-     * - `to` cannot be the zero address.
+      * - `from` cannot be the zero address.
+      * - `to` cannot be the zero address.
       * - `tokenId` token must exist and be owned by `from`.
       * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
       * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.

+ 28 - 26
contracts/token/ERC777/ERC777.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../../GSN/Context.sol";
+import "../../utils/Context.sol";
 import "./IERC777.sol";
 import "./IERC777Recipient.sol";
 import "./IERC777Sender.sol";
@@ -85,14 +85,14 @@ contract ERC777 is Context, IERC777, IERC20 {
     /**
      * @dev See {IERC777-name}.
      */
-    function name() public view override returns (string memory) {
+    function name() public view virtual override returns (string memory) {
         return _name;
     }
 
     /**
      * @dev See {IERC777-symbol}.
      */
-    function symbol() public view override returns (string memory) {
+    function symbol() public view virtual override returns (string memory) {
         return _symbol;
     }
 
@@ -102,7 +102,7 @@ contract ERC777 is Context, IERC777, IERC20 {
      * Always returns 18, as per the
      * [ERC777 EIP](https://eips.ethereum.org/EIPS/eip-777#backward-compatibility).
      */
-    function decimals() public pure returns (uint8) {
+    function decimals() public pure virtual returns (uint8) {
         return 18;
     }
 
@@ -111,21 +111,21 @@ contract ERC777 is Context, IERC777, IERC20 {
      *
      * This implementation always returns `1`.
      */
-    function granularity() public view override returns (uint256) {
+    function granularity() public view virtual override returns (uint256) {
         return 1;
     }
 
     /**
      * @dev See {IERC777-totalSupply}.
      */
-    function totalSupply() public view override(IERC20, IERC777) returns (uint256) {
+    function totalSupply() public view virtual override(IERC20, IERC777) returns (uint256) {
         return _totalSupply;
     }
 
     /**
      * @dev Returns the amount of tokens owned by an account (`tokenHolder`).
      */
-    function balanceOf(address tokenHolder) public view override(IERC20, IERC777) returns (uint256) {
+    function balanceOf(address tokenHolder) public view virtual override(IERC20, IERC777) returns (uint256) {
         return _balances[tokenHolder];
     }
 
@@ -134,7 +134,7 @@ contract ERC777 is Context, IERC777, IERC20 {
      *
      * Also emits a {IERC20-Transfer} event for ERC20 compatibility.
      */
-    function send(address recipient, uint256 amount, bytes memory data) public override  {
+    function send(address recipient, uint256 amount, bytes memory data) public virtual override  {
         _send(_msgSender(), recipient, amount, data, "", true);
     }
 
@@ -146,7 +146,7 @@ contract ERC777 is Context, IERC777, IERC20 {
      *
      * Also emits a {Sent} event.
      */
-    function transfer(address recipient, uint256 amount) public override returns (bool) {
+    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
         require(recipient != address(0), "ERC777: transfer to the zero address");
 
         address from = _msgSender();
@@ -165,17 +165,14 @@ contract ERC777 is Context, IERC777, IERC20 {
      *
      * Also emits a {IERC20-Transfer} event for ERC20 compatibility.
      */
-    function burn(uint256 amount, bytes memory data) public override  {
+    function burn(uint256 amount, bytes memory data) public virtual override  {
         _burn(_msgSender(), amount, data, "");
     }
 
     /**
      * @dev See {IERC777-isOperatorFor}.
      */
-    function isOperatorFor(
-        address operator,
-        address tokenHolder
-    ) public view override returns (bool) {
+    function isOperatorFor(address operator, address tokenHolder) public view virtual override returns (bool) {
         return operator == tokenHolder ||
             (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||
             _operators[tokenHolder][operator];
@@ -184,7 +181,7 @@ contract ERC777 is Context, IERC777, IERC20 {
     /**
      * @dev See {IERC777-authorizeOperator}.
      */
-    function authorizeOperator(address operator) public override  {
+    function authorizeOperator(address operator) public virtual override  {
         require(_msgSender() != operator, "ERC777: authorizing self as operator");
 
         if (_defaultOperators[operator]) {
@@ -199,7 +196,7 @@ contract ERC777 is Context, IERC777, IERC20 {
     /**
      * @dev See {IERC777-revokeOperator}.
      */
-    function revokeOperator(address operator) public override  {
+    function revokeOperator(address operator) public virtual override  {
         require(operator != _msgSender(), "ERC777: revoking self as operator");
 
         if (_defaultOperators[operator]) {
@@ -214,7 +211,7 @@ contract ERC777 is Context, IERC777, IERC20 {
     /**
      * @dev See {IERC777-defaultOperators}.
      */
-    function defaultOperators() public view override returns (address[] memory) {
+    function defaultOperators() public view virtual override returns (address[] memory) {
         return _defaultOperatorsArray;
     }
 
@@ -230,7 +227,9 @@ contract ERC777 is Context, IERC777, IERC20 {
         bytes memory data,
         bytes memory operatorData
     )
-    public override
+        public
+        virtual
+        override
     {
         require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder");
         _send(sender, recipient, amount, data, operatorData, true);
@@ -241,7 +240,7 @@ contract ERC777 is Context, IERC777, IERC20 {
      *
      * Emits {Burned} and {IERC20-Transfer} events.
      */
-    function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public override {
+    function operatorBurn(address account, uint256 amount, bytes memory data, bytes memory operatorData) public virtual override {
         require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder");
         _burn(account, amount, data, operatorData);
     }
@@ -253,7 +252,7 @@ contract ERC777 is Context, IERC777, IERC20 {
      * not have allowance, and accounts with allowance may not be operators
      * themselves.
      */
-    function allowance(address holder, address spender) public view override returns (uint256) {
+    function allowance(address holder, address spender) public view virtual override returns (uint256) {
         return _allowances[holder][spender];
     }
 
@@ -262,7 +261,7 @@ contract ERC777 is Context, IERC777, IERC20 {
      *
      * Note that accounts cannot have allowance issued by their operators.
      */
-    function approve(address spender, uint256 value) public override returns (bool) {
+    function approve(address spender, uint256 value) public virtual override returns (bool) {
         address holder = _msgSender();
         _approve(holder, spender, value);
         return true;
@@ -277,7 +276,7 @@ contract ERC777 is Context, IERC777, IERC20 {
     *
     * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.
     */
-    function transferFrom(address holder, address recipient, uint256 amount) public override returns (bool) {
+    function transferFrom(address holder, address recipient, uint256 amount) public virtual override returns (bool) {
         require(recipient != address(0), "ERC777: transfer to the zero address");
         require(holder != address(0), "ERC777: transfer from the zero address");
 
@@ -316,7 +315,8 @@ contract ERC777 is Context, IERC777, IERC20 {
         bytes memory userData,
         bytes memory operatorData
     )
-    internal virtual
+        internal
+        virtual
     {
         require(account != address(0), "ERC777: mint to the zero address");
 
@@ -352,6 +352,7 @@ contract ERC777 is Context, IERC777, IERC20 {
         bool requireReceptionAck
     )
         internal
+        virtual
     {
         require(from != address(0), "ERC777: send from the zero address");
         require(to != address(0), "ERC777: send to the zero address");
@@ -378,16 +379,17 @@ contract ERC777 is Context, IERC777, IERC20 {
         bytes memory data,
         bytes memory operatorData
     )
-        internal virtual
+        internal
+        virtual
     {
         require(from != address(0), "ERC777: burn from the zero address");
 
         address operator = _msgSender();
 
-        _beforeTokenTransfer(operator, from, address(0), amount);
-
         _callTokensToSend(operator, from, address(0), amount, data, operatorData);
 
+        _beforeTokenTransfer(operator, from, address(0), amount);
+
         // Update state variables
         _balances[from] = _balances[from] - amount;
         _totalSupply = _totalSupply - amount;

+ 24 - 0
contracts/utils/Context.sol

@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity >=0.6.0 <0.9.0;
+
+/*
+ * @dev Provides information about the current execution context, including the
+ * sender of the transaction and its data. While these are generally available
+ * via msg.sender and msg.data, they should not be accessed in such a direct
+ * manner, since when dealing with GSN meta-transactions the account sending and
+ * paying for execution may not be the actual sender (as far as an application
+ * is concerned).
+ *
+ * This contract is only required for intermediate, library-like contracts.
+ */
+abstract contract Context {
+    function _msgSender() internal view virtual returns (address) {
+        return msg.sender;
+    }
+
+    function _msgData() internal view virtual returns (bytes memory) {
+        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
+        return msg.data;
+    }
+}

+ 28 - 1
contracts/utils/EnumerableMap.sol

@@ -143,6 +143,16 @@ library EnumerableMap {
         return (entry._key, entry._value);
     }
 
+    /**
+     * @dev Tries to returns the value associated with `key`.  O(1).
+     * Does not revert if `key` is not in the map.
+     */
+    function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {
+        uint256 keyIndex = map._indexes[key];
+        if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
+        return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
+    }
+
     /**
      * @dev Returns the value associated with `key`.  O(1).
      *
@@ -151,11 +161,16 @@ library EnumerableMap {
      * - `key` must be in the map.
      */
     function _get(Map storage map, bytes32 key) private view returns (bytes32) {
-        return _get(map, key, "EnumerableMap: nonexistent key");
+        uint256 keyIndex = map._indexes[key];
+        require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
+        return map._entries[keyIndex - 1]._value; // All indexes are 1-based
     }
 
     /**
      * @dev Same as {_get}, with a custom error message when `key` is not in the map.
+     *
+     * CAUTION: This function is deprecated because it requires allocating memory for the error
+     * message unnecessarily. For custom revert reasons use {_tryGet}.
      */
     function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
         uint256 keyIndex = map._indexes[key];
@@ -217,6 +232,15 @@ library EnumerableMap {
         return (uint256(key), address(uint160(uint256(value))));
     }
 
+    /**
+     * @dev Tries to returns the value associated with `key`.  O(1).
+     * Does not revert if `key` is not in the map.
+     */
+    function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
+        (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
+        return (success, address(uint160(uint256(value))));
+    }
+
     /**
      * @dev Returns the value associated with `key`.  O(1).
      *
@@ -230,6 +254,9 @@ library EnumerableMap {
 
     /**
      * @dev Same as {get}, with a custom error message when `key` is not in the map.
+     *
+     * CAUTION: This function is deprecated because it requires allocating memory for the error
+     * message unnecessarily. For custom revert reasons use {tryGet}.
      */
     function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
         return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));

+ 4 - 4
contracts/utils/Pausable.sol

@@ -2,7 +2,7 @@
 
 pragma solidity ^0.8.0;
 
-import "../GSN/Context.sol";
+import "./Context.sol";
 
 /**
  * @dev Contract module which allows children to implement an emergency stop
@@ -36,7 +36,7 @@ abstract contract Pausable is Context {
     /**
      * @dev Returns true if the contract is paused, and false otherwise.
      */
-    function paused() public view returns (bool) {
+    function paused() public view virtual returns (bool) {
         return _paused;
     }
 
@@ -48,7 +48,7 @@ abstract contract Pausable is Context {
      * - The contract must not be paused.
      */
     modifier whenNotPaused() {
-        require(!_paused, "Pausable: paused");
+        require(!paused(), "Pausable: paused");
         _;
     }
 
@@ -60,7 +60,7 @@ abstract contract Pausable is Context {
      * - The contract must be paused.
      */
     modifier whenPaused() {
-        require(_paused, "Pausable: not paused");
+        require(paused(), "Pausable: not paused");
         _;
     }
 

+ 2 - 2
docs/modules/ROOT/pages/access-control.adoc

@@ -71,7 +71,7 @@ contract MyToken is ERC20, AccessControl {
     // Create a new role identifier for the minter role
     bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
 
-    constructor(address minter) public ERC20("MyToken", "TKN") {
+    constructor(address minter) ERC20("MyToken", "TKN") {
         // Grant the minter role to a specified account
         _setupRole(MINTER_ROLE, minter);
     }
@@ -103,7 +103,7 @@ contract MyToken is ERC20, AccessControl {
     bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
     bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
 
-    constructor(address minter, address burner) public ERC20("MyToken", "TKN") {
+    constructor(address minter, address burner) ERC20("MyToken", "TKN") {
         _setupRole(MINTER_ROLE, minter);
         _setupRole(BURNER_ROLE, burner);
     }

+ 1 - 1
docs/modules/ROOT/pages/erc20-supply.adoc

@@ -68,7 +68,7 @@ The accounts with the minter role don't need to be externally owned, though, and
 contract MinerRewardMinter {
     ERC20PresetMinterPauser _token;
 
-    constructor(ERC20PresetMinterPauser token) public {
+    constructor(ERC20PresetMinterPauser token) {
         _token = token;
     }
 

+ 1 - 1
docs/modules/ROOT/pages/erc20.adoc

@@ -20,7 +20,7 @@ pragma solidity ^0.8.0;
 import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
 
 contract GLDToken is ERC20 {
-    constructor(uint256 initialSupply) public ERC20("Gold", "GLD") {
+    constructor(uint256 initialSupply) ERC20("Gold", "GLD") {
         _mint(msg.sender, initialSupply);
     }
 }

+ 0 - 1
docs/modules/ROOT/pages/erc777.adoc

@@ -26,7 +26,6 @@ import "@openzeppelin/contracts/token/ERC777/ERC777.sol";
 
 contract GLDToken is ERC777 {
     constructor(uint256 initialSupply, address[] memory defaultOperators)
-        public
         ERC777("Gold", "GLD", defaultOperators)
     {
         _mint(msg.sender, initialSupply, "", "");

+ 1 - 1
docs/modules/ROOT/pages/gsn-strategies.adoc

@@ -62,7 +62,7 @@ Instead of using `GSNRecipient` directly, your GSN recipient contract will inste
 import "@openzeppelin/contracts/GSN/GSNRecipientSignature.sol";
 
 contract MyContract is GSNRecipientSignature {
-    constructor(address trustedSigner) public GSNRecipientSignature(trustedSigner) {
+    constructor(address trustedSigner) GSNRecipientSignature(trustedSigner) {
     }
 }
 ----

+ 1 - 1
docs/modules/ROOT/pages/index.adoc

@@ -33,7 +33,7 @@ pragma solidity ^0.8.0;
 import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
 
 contract MyNFT is ERC721 {
-    constructor() ERC721("MyNFT", "MNFT") public {
+    constructor() ERC721("MyNFT", "MNFT") {
     }
 }
 ----

Fichier diff supprimé car celui-ci est trop grand
+ 389 - 960
package-lock.json


+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
   "name": "openzeppelin-solidity",
   "description": "Secure Smart Contract library for Solidity",
-  "version": "3.3.0",
+  "version": "3.3.0-solc-0.8",
   "files": [
     "/contracts/**/*.sol",
     "/build/contracts/*.json",

+ 1 - 1
scripts/prepare-docs.sh

@@ -15,6 +15,6 @@ solidity-docgen \
   -o "$OUTDIR" \
   -e contracts/mocks,contracts/examples \
   --output-structure readmes \
-  --solc-module scripts/prepare-docs-solc.js
+  --solc-module ./scripts/prepare-docs-solc.js
 
 node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc"

+ 52 - 0
test/introspection/ERC165Checker.test.js

@@ -37,6 +37,12 @@ contract('ERC165Checker', function (accounts) {
       const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
       expect(supported).to.equal(false);
     });
+
+    it('does not support mock interface via getSupportedInterfaces', async function () {
+      const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
+      expect(supported.length).to.equal(1);
+      expect(supported[0]).to.equal(false);
+    });
   });
 
   context('ERC165 supported', function () {
@@ -58,6 +64,12 @@ contract('ERC165Checker', function (accounts) {
       const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
       expect(supported).to.equal(false);
     });
+
+    it('does not support mock interface via getSupportedInterfaces', async function () {
+      const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
+      expect(supported.length).to.equal(1);
+      expect(supported[0]).to.equal(false);
+    });
   });
 
   context('ERC165 and single interface supported', function () {
@@ -79,6 +91,12 @@ contract('ERC165Checker', function (accounts) {
       const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
       expect(supported).to.equal(true);
     });
+
+    it('supports mock interface via getSupportedInterfaces', async function () {
+      const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
+      expect(supported.length).to.equal(1);
+      expect(supported[0]).to.equal(true);
+    });
   });
 
   context('ERC165 and many interfaces supported', function () {
@@ -117,6 +135,34 @@ contract('ERC165Checker', function (accounts) {
       const supported = await this.mock.supportsAllInterfaces(this.target.address, interfaceIdsToTest);
       expect(supported).to.equal(false);
     });
+
+    it('supports all interfaceIds via getSupportedInterfaces', async function () {
+      const supported = await this.mock.getSupportedInterfaces(this.target.address, this.supportedInterfaces);
+      expect(supported.length).to.equal(3);
+      expect(supported[0]).to.equal(true);
+      expect(supported[1]).to.equal(true);
+      expect(supported[2]).to.equal(true);
+    });
+
+    it('supports none of the interfaces queried via getSupportedInterfaces', async function () {
+      const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2];
+
+      const supported = await this.mock.getSupportedInterfaces(this.target.address, interfaceIdsToTest);
+      expect(supported.length).to.equal(2);
+      expect(supported[0]).to.equal(false);
+      expect(supported[1]).to.equal(false);
+    });
+
+    it('supports not all of the interfaces queried via getSupportedInterfaces', async function () {
+      const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID];
+
+      const supported = await this.mock.getSupportedInterfaces(this.target.address, interfaceIdsToTest);
+      expect(supported.length).to.equal(4);
+      expect(supported[0]).to.equal(true);
+      expect(supported[1]).to.equal(true);
+      expect(supported[2]).to.equal(true);
+      expect(supported[3]).to.equal(false);
+    });
   });
 
   context('account address does not support ERC165', function () {
@@ -134,5 +180,11 @@ contract('ERC165Checker', function (accounts) {
       const supported = await this.mock.supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]);
       expect(supported).to.equal(false);
     });
+
+    it('does not support mock interface via getSupportedInterfaces', async function () {
+      const supported = await this.mock.getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]);
+      expect(supported.length).to.equal(1);
+      expect(supported[0]).to.equal(false);
+    });
   });
 });

+ 332 - 75
test/math/SafeMath.test.js

@@ -5,142 +5,399 @@ const { expect } = require('chai');
 
 const SafeMathMock = artifacts.require('SafeMathMock');
 
+function expectStruct (value, expected) {
+  for (const key in expected) {
+    if (BN.isBN(value[key])) {
+      expect(value[key]).to.be.bignumber.equal(expected[key]);
+    } else {
+      expect(value[key]).to.be.equal(expected[key]);
+    }
+  }
+}
+
 contract('SafeMath', function (accounts) {
   beforeEach(async function () {
     this.safeMath = await SafeMathMock.new();
   });
 
-  async function testCommutative (fn, lhs, rhs, expected) {
-    expect(await fn(lhs, rhs)).to.be.bignumber.equal(expected);
-    expect(await fn(rhs, lhs)).to.be.bignumber.equal(expected);
+  async function testCommutative (fn, lhs, rhs, expected, ...extra) {
+    expect(await fn(lhs, rhs, ...extra)).to.be.bignumber.equal(expected);
+    expect(await fn(rhs, lhs, ...extra)).to.be.bignumber.equal(expected);
   }
 
-  async function testFailsCommutative (fn, lhs, rhs) {
-    await expectRevert.unspecified(fn(lhs, rhs));
-    await expectRevert.unspecified(fn(rhs, lhs));
+  async function testFailsCommutative (fn, lhs, rhs, reason, ...extra) {
+    if (reason == undefined) {
+      await expectRevert.unspecified(fn(lhs, rhs, ...extra));
+      await expectRevert.unspecified(fn(rhs, lhs, ...extra));
+    } else {
+      await expectRevert(fn(lhs, rhs, ...extra), reason);
+      await expectRevert(fn(rhs, lhs, ...extra), reason);
+    }
   }
 
-  describe('add', function () {
-    it('adds correctly', async function () {
-      const a = new BN('5678');
-      const b = new BN('1234');
+  async function testCommutativeIterable (fn, lhs, rhs, expected, ...extra) {
+    expectStruct(await fn(lhs, rhs, ...extra), expected);
+    expectStruct(await fn(rhs, lhs, ...extra), expected);
+  }
 
-      await testCommutative(this.safeMath.add, a, b, a.add(b));
-    });
+  describe('with flag', function () {
+    describe('add', function () {
+      it('adds correctly', async function () {
+        const a = new BN('5678');
+        const b = new BN('1234');
 
-    it('reverts on addition overflow', async function () {
-      const a = MAX_UINT256;
-      const b = new BN('1');
+        testCommutativeIterable(this.safeMath.tryAdd, a, b, { flag: true, value: a.add(b) });
+      });
+
+      it('reverts on addition overflow', async function () {
+        const a = MAX_UINT256;
+        const b = new BN('1');
 
-      await testFailsCommutative(this.safeMath.add, a, b);
+        testCommutativeIterable(this.safeMath.tryAdd, a, b, { flag: false, value: '0' });
+      });
     });
-  });
 
-  describe('sub', function () {
-    it('subtracts correctly', async function () {
-      const a = new BN('5678');
-      const b = new BN('1234');
+    describe('sub', function () {
+      it('subtracts correctly', async function () {
+        const a = new BN('5678');
+        const b = new BN('1234');
 
-      expect(await this.safeMath.sub(a, b)).to.be.bignumber.equal(a.sub(b));
-    });
+        expectStruct(await this.safeMath.trySub(a, b), { flag: true, value: a.sub(b) });
+      });
 
-    it('reverts if subtraction result would be negative', async function () {
-      const a = new BN('1234');
-      const b = new BN('5678');
+      it('reverts if subtraction result would be negative', async function () {
+        const a = new BN('1234');
+        const b = new BN('5678');
 
-      await expectRevert.unspecified(this.safeMath.sub(a, b));
+        expectStruct(await this.safeMath.trySub(a, b), { flag: false, value: '0' });
+      });
     });
-  });
 
-  describe('mul', function () {
-    it('multiplies correctly', async function () {
-      const a = new BN('1234');
-      const b = new BN('5678');
+    describe('mul', function () {
+      it('multiplies correctly', async function () {
+        const a = new BN('1234');
+        const b = new BN('5678');
+
+        testCommutativeIterable(this.safeMath.tryMul, a, b, { flag: true, value: a.mul(b) });
+      });
+
+      it('multiplies by zero correctly', async function () {
+        const a = new BN('0');
+        const b = new BN('5678');
+
+        testCommutativeIterable(this.safeMath.tryMul, a, b, { flag: true, value: a.mul(b) });
+      });
 
-      await testCommutative(this.safeMath.mul, a, b, a.mul(b));
+      it('reverts on multiplication overflow', async function () {
+        const a = MAX_UINT256;
+        const b = new BN('2');
+
+        testCommutativeIterable(this.safeMath.tryMul, a, b, { flag: false, value: '0' });
+      });
     });
 
-    it('multiplies by zero correctly', async function () {
-      const a = new BN('0');
-      const b = new BN('5678');
+    describe('div', function () {
+      it('divides correctly', async function () {
+        const a = new BN('5678');
+        const b = new BN('5678');
 
-      await testCommutative(this.safeMath.mul, a, b, '0');
+        expectStruct(await this.safeMath.tryDiv(a, b), { flag: true, value: a.div(b) });
+      });
+
+      it('divides zero correctly', async function () {
+        const a = new BN('0');
+        const b = new BN('5678');
+
+        expectStruct(await this.safeMath.tryDiv(a, b), { flag: true, value: a.div(b) });
+      });
+
+      it('returns complete number result on non-even division', async function () {
+        const a = new BN('7000');
+        const b = new BN('5678');
+
+        expectStruct(await this.safeMath.tryDiv(a, b), { flag: true, value: a.div(b) });
+      });
+
+      it('reverts on division by zero', async function () {
+        const a = new BN('5678');
+        const b = new BN('0');
+
+        expectStruct(await this.safeMath.tryDiv(a, b), { flag: false, value: '0' });
+      });
     });
 
-    it('reverts on multiplication overflow', async function () {
-      const a = MAX_UINT256;
-      const b = new BN('2');
+    describe('mod', function () {
+      describe('modulos correctly', async function () {
+        it('when the dividend is smaller than the divisor', async function () {
+          const a = new BN('284');
+          const b = new BN('5678');
+
+          expectStruct(await this.safeMath.tryMod(a, b), { flag: true, value: a.mod(b) });
+        });
+
+        it('when the dividend is equal to the divisor', async function () {
+          const a = new BN('5678');
+          const b = new BN('5678');
+
+          expectStruct(await this.safeMath.tryMod(a, b), { flag: true, value: a.mod(b) });
+        });
 
-      await testFailsCommutative(this.safeMath.mul, a, b);
+        it('when the dividend is larger than the divisor', async function () {
+          const a = new BN('7000');
+          const b = new BN('5678');
+
+          expectStruct(await this.safeMath.tryMod(a, b), { flag: true, value: a.mod(b) });
+        });
+
+        it('when the dividend is a multiple of the divisor', async function () {
+          const a = new BN('17034'); // 17034 == 5678 * 3
+          const b = new BN('5678');
+
+          expectStruct(await this.safeMath.tryMod(a, b), { flag: true, value: a.mod(b) });
+        });
+      });
+
+      it('reverts with a 0 divisor', async function () {
+        const a = new BN('5678');
+        const b = new BN('0');
+
+        expectStruct(await this.safeMath.tryMod(a, b), { flag: false, value: '0' });
+      });
     });
   });
 
-  describe('div', function () {
-    it('divides correctly', async function () {
-      const a = new BN('5678');
-      const b = new BN('5678');
+  describe('with default revert message', function () {
+    describe('add', function () {
+      it('adds correctly', async function () {
+        const a = new BN('5678');
+        const b = new BN('1234');
+
+        await testCommutative(this.safeMath.add, a, b, a.add(b));
+      });
+
+      it('reverts on addition overflow', async function () {
+        const a = MAX_UINT256;
+        const b = new BN('1');
+
+        await testFailsCommutative(this.safeMath.add, a, b, undefined);
+      });
+    });
+
+    describe('sub', function () {
+      it('subtracts correctly', async function () {
+        const a = new BN('5678');
+        const b = new BN('1234');
+
+        expect(await this.safeMath.sub(a, b)).to.be.bignumber.equal(a.sub(b));
+      });
+
+      it('reverts if subtraction result would be negative', async function () {
+        const a = new BN('1234');
+        const b = new BN('5678');
 
-      expect(await this.safeMath.div(a, b)).to.be.bignumber.equal(a.div(b));
+        await expectRevert.unspecified(this.safeMath.sub(a, b));
+      });
     });
 
-    it('divides zero correctly', async function () {
-      const a = new BN('0');
-      const b = new BN('5678');
+    describe('mul', function () {
+      it('multiplies correctly', async function () {
+        const a = new BN('1234');
+        const b = new BN('5678');
+
+        await testCommutative(this.safeMath.mul, a, b, a.mul(b));
+      });
+
+      it('multiplies by zero correctly', async function () {
+        const a = new BN('0');
+        const b = new BN('5678');
+
+        await testCommutative(this.safeMath.mul, a, b, '0');
+      });
 
-      expect(await this.safeMath.div(a, b)).to.be.bignumber.equal('0');
+      it('reverts on multiplication overflow', async function () {
+        const a = MAX_UINT256;
+        const b = new BN('2');
+
+        await testFailsCommutative(this.safeMath.mul, a, b, undefined);
+      });
     });
 
-    it('returns complete number result on non-even division', async function () {
-      const a = new BN('7000');
-      const b = new BN('5678');
+    describe('div', function () {
+      it('divides correctly', async function () {
+        const a = new BN('5678');
+        const b = new BN('5678');
+
+        expect(await this.safeMath.div(a, b)).to.be.bignumber.equal(a.div(b));
+      });
+
+      it('divides zero correctly', async function () {
+        const a = new BN('0');
+        const b = new BN('5678');
+
+        expect(await this.safeMath.div(a, b)).to.be.bignumber.equal('0');
+      });
+
+      it('returns complete number result on non-even division', async function () {
+        const a = new BN('7000');
+        const b = new BN('5678');
+
+        expect(await this.safeMath.div(a, b)).to.be.bignumber.equal('1');
+      });
+
+      it('reverts on division by zero', async function () {
+        const a = new BN('5678');
+        const b = new BN('0');
 
-      expect(await this.safeMath.div(a, b)).to.be.bignumber.equal('1');
+        await expectRevert.unspecified(this.safeMath.div(a, b));
+      });
     });
 
-    it('reverts on division by zero', async function () {
-      const a = new BN('5678');
-      const b = new BN('0');
+    describe('mod', function () {
+      describe('modulos correctly', async function () {
+        it('when the dividend is smaller than the divisor', async function () {
+          const a = new BN('284');
+          const b = new BN('5678');
+
+          expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b));
+        });
+
+        it('when the dividend is equal to the divisor', async function () {
+          const a = new BN('5678');
+          const b = new BN('5678');
+
+          expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b));
+        });
 
-      await expectRevert.unspecified(this.safeMath.div(a, b));
+        it('when the dividend is larger than the divisor', async function () {
+          const a = new BN('7000');
+          const b = new BN('5678');
+
+          expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b));
+        });
+
+        it('when the dividend is a multiple of the divisor', async function () {
+          const a = new BN('17034'); // 17034 == 5678 * 3
+          const b = new BN('5678');
+
+          expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b));
+        });
+      });
+
+      it('reverts with a 0 divisor', async function () {
+        const a = new BN('5678');
+        const b = new BN('0');
+
+        await expectRevert.unspecified(this.safeMath.mod(a, b));
+      });
     });
   });
 
-  describe('mod', function () {
-    describe('modulos correctly', async function () {
-      it('when the dividend is smaller than the divisor', async function () {
-        const a = new BN('284');
+  describe('with custom revert message', function () {
+    describe('sub', function () {
+      it('subtracts correctly', async function () {
+        const a = new BN('5678');
+        const b = new BN('1234');
+
+        expect(await this.safeMath.subWithMessage(a, b, 'MyErrorMessage')).to.be.bignumber.equal(a.sub(b));
+      });
+
+      it('reverts if subtraction result would be negative', async function () {
+        const a = new BN('1234');
         const b = new BN('5678');
 
-        expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b));
+        await expectRevert(this.safeMath.subWithMessage(a, b, 'MyErrorMessage'), 'MyErrorMessage');
       });
+    });
 
-      it('when the dividend is equal to the divisor', async function () {
+    describe('div', function () {
+      it('divides correctly', async function () {
         const a = new BN('5678');
         const b = new BN('5678');
 
-        expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b));
+        expect(await this.safeMath.divWithMessage(a, b, 'MyErrorMessage')).to.be.bignumber.equal(a.div(b));
       });
 
-      it('when the dividend is larger than the divisor', async function () {
-        const a = new BN('7000');
+      it('divides zero correctly', async function () {
+        const a = new BN('0');
         const b = new BN('5678');
 
-        expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b));
+        expect(await this.safeMath.divWithMessage(a, b, 'MyErrorMessage')).to.be.bignumber.equal('0');
       });
 
-      it('when the dividend is a multiple of the divisor', async function () {
-        const a = new BN('17034'); // 17034 == 5678 * 3
+      it('returns complete number result on non-even division', async function () {
+        const a = new BN('7000');
         const b = new BN('5678');
 
-        expect(await this.safeMath.mod(a, b)).to.be.bignumber.equal(a.mod(b));
+        expect(await this.safeMath.divWithMessage(a, b, 'MyErrorMessage')).to.be.bignumber.equal('1');
+      });
+
+      it('reverts on division by zero', async function () {
+        const a = new BN('5678');
+        const b = new BN('0');
+
+        await expectRevert(this.safeMath.divWithMessage(a, b, 'MyErrorMessage'), 'MyErrorMessage');
       });
     });
 
-    it('reverts with a 0 divisor', async function () {
-      const a = new BN('5678');
-      const b = new BN('0');
+    describe('mod', function () {
+      describe('modulos correctly', async function () {
+        it('when the dividend is smaller than the divisor', async function () {
+          const a = new BN('284');
+          const b = new BN('5678');
+
+          expect(await this.safeMath.modWithMessage(a, b, 'MyErrorMessage')).to.be.bignumber.equal(a.mod(b));
+        });
+
+        it('when the dividend is equal to the divisor', async function () {
+          const a = new BN('5678');
+          const b = new BN('5678');
+
+          expect(await this.safeMath.modWithMessage(a, b, 'MyErrorMessage')).to.be.bignumber.equal(a.mod(b));
+        });
+
+        it('when the dividend is larger than the divisor', async function () {
+          const a = new BN('7000');
+          const b = new BN('5678');
+
+          expect(await this.safeMath.modWithMessage(a, b, 'MyErrorMessage')).to.be.bignumber.equal(a.mod(b));
+        });
+
+        it('when the dividend is a multiple of the divisor', async function () {
+          const a = new BN('17034'); // 17034 == 5678 * 3
+          const b = new BN('5678');
+
+          expect(await this.safeMath.modWithMessage(a, b, 'MyErrorMessage')).to.be.bignumber.equal(a.mod(b));
+        });
+      });
+
+      it('reverts with a 0 divisor', async function () {
+        const a = new BN('5678');
+        const b = new BN('0');
+
+        await expectRevert(this.safeMath.modWithMessage(a, b, 'MyErrorMessage'), 'MyErrorMessage');
+      });
+    });
+  });
+
+  describe('memory leakage', function () {
+    it('add', async function () {
+      expect(await this.safeMath.addMemoryCheck()).to.be.bignumber.equal('0');
+    });
+
+    it('sub', async function () {
+      expect(await this.safeMath.subMemoryCheck()).to.be.bignumber.equal('0');
+    });
+
+    it('mul', async function () {
+      expect(await this.safeMath.mulMemoryCheck()).to.be.bignumber.equal('0');
+    });
+
+    it('div', async function () {
+      expect(await this.safeMath.divMemoryCheck()).to.be.bignumber.equal('0');
+    });
 
-      await expectRevert.unspecified(this.safeMath.mod(a, b));
+    it('mod', async function () {
+      expect(await this.safeMath.modMemoryCheck()).to.be.bignumber.equal('0');
     });
   });
 });

+ 150 - 0
test/proxy/Clones.behaviour.js

@@ -0,0 +1,150 @@
+const { expectRevert } = require('@openzeppelin/test-helpers');
+
+const { expect } = require('chai');
+
+const DummyImplementation = artifacts.require('DummyImplementation');
+
+module.exports = function shouldBehaveLikeClone (createClone) {
+  before('deploy implementation', async function () {
+    this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address);
+  });
+
+  const assertProxyInitialization = function ({ value, balance }) {
+    it('initializes the proxy', async function () {
+      const dummy = new DummyImplementation(this.proxy);
+      expect(await dummy.value()).to.be.bignumber.equal(value.toString());
+    });
+
+    it('has expected balance', async function () {
+      expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString());
+    });
+  };
+
+  describe('initialization without parameters', function () {
+    describe('non payable', function () {
+      const expectedInitializedValue = 10;
+      const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI();
+
+      describe('when not sending balance', function () {
+        beforeEach('creating proxy', async function () {
+          this.proxy = (
+            await createClone(this.implementation, initializeData)
+          ).address;
+        });
+
+        assertProxyInitialization({
+          value: expectedInitializedValue,
+          balance: 0,
+        });
+      });
+
+      describe('when sending some balance', function () {
+        const value = 10e5;
+
+        it('reverts', async function () {
+          await expectRevert.unspecified(
+            createClone(this.implementation, initializeData, { value }),
+          );
+        });
+      });
+    });
+
+    describe('payable', function () {
+      const expectedInitializedValue = 100;
+      const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI();
+
+      describe('when not sending balance', function () {
+        beforeEach('creating proxy', async function () {
+          this.proxy = (
+            await createClone(this.implementation, initializeData)
+          ).address;
+        });
+
+        assertProxyInitialization({
+          value: expectedInitializedValue,
+          balance: 0,
+        });
+      });
+
+      describe('when sending some balance', function () {
+        const value = 10e5;
+
+        beforeEach('creating proxy', async function () {
+          this.proxy = (
+            await createClone(this.implementation, initializeData, { value })
+          ).address;
+        });
+
+        assertProxyInitialization({
+          value: expectedInitializedValue,
+          balance: value,
+        });
+      });
+    });
+  });
+
+  describe('initialization with parameters', function () {
+    describe('non payable', function () {
+      const expectedInitializedValue = 10;
+      const initializeData = new DummyImplementation('').contract
+        .methods.initializeNonPayableWithValue(expectedInitializedValue).encodeABI();
+
+      describe('when not sending balance', function () {
+        beforeEach('creating proxy', async function () {
+          this.proxy = (
+            await createClone(this.implementation, initializeData)
+          ).address;
+        });
+
+        assertProxyInitialization({
+          value: expectedInitializedValue,
+          balance: 0,
+        });
+      });
+
+      describe('when sending some balance', function () {
+        const value = 10e5;
+
+        it('reverts', async function () {
+          await expectRevert.unspecified(
+            createClone(this.implementation, initializeData, { value }),
+          );
+        });
+      });
+    });
+
+    describe('payable', function () {
+      const expectedInitializedValue = 42;
+      const initializeData = new DummyImplementation('').contract
+        .methods.initializePayableWithValue(expectedInitializedValue).encodeABI();
+
+      describe('when not sending balance', function () {
+        beforeEach('creating proxy', async function () {
+          this.proxy = (
+            await createClone(this.implementation, initializeData)
+          ).address;
+        });
+
+        assertProxyInitialization({
+          value: expectedInitializedValue,
+          balance: 0,
+        });
+      });
+
+      describe('when sending some balance', function () {
+        const value = 10e5;
+
+        beforeEach('creating proxy', async function () {
+          this.proxy = (
+            await createClone(this.implementation, initializeData, { value })
+          ).address;
+        });
+
+        assertProxyInitialization({
+          value: expectedInitializedValue,
+          balance: value,
+        });
+      });
+    });
+  });
+};

+ 54 - 0
test/proxy/Clones.test.js

@@ -0,0 +1,54 @@
+const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
+
+const shouldBehaveLikeClone = require('./Clones.behaviour');
+
+const ClonesMock = artifacts.require('ClonesMock');
+
+contract('Clones', function (accounts) {
+  describe('clone', function () {
+    shouldBehaveLikeClone(async (implementation, initData, opts = {}) => {
+      const factory = await ClonesMock.new();
+      const receipt = await factory.clone(implementation, initData, { value: opts.value });
+      const address = receipt.logs.find(({ event }) => event === 'NewInstance').args.instance;
+      return { address };
+    });
+  });
+
+  describe('cloneDeterministic', function () {
+    shouldBehaveLikeClone(async (implementation, initData, opts = {}) => {
+      const salt = web3.utils.randomHex(32);
+      const factory = await ClonesMock.new();
+      const receipt = await factory.cloneDeterministic(implementation, salt, initData, { value: opts.value });
+      const address = receipt.logs.find(({ event }) => event === 'NewInstance').args.instance;
+      return { address };
+    });
+
+    it('address already used', async function () {
+      const implementation = web3.utils.randomHex(20);
+      const salt = web3.utils.randomHex(32);
+      const factory = await ClonesMock.new();
+      // deploy once
+      expectEvent(
+        await factory.cloneDeterministic(implementation, salt, '0x'),
+        'NewInstance',
+      );
+      // deploy twice
+      await expectRevert(
+        factory.cloneDeterministic(implementation, salt, '0x'),
+        'ERC1167: create2 failed',
+      );
+    });
+
+    it('address prediction', async function () {
+      const implementation = web3.utils.randomHex(20);
+      const salt = web3.utils.randomHex(32);
+      const factory = await ClonesMock.new();
+      const predicted = await factory.predictDeterministicAddress(implementation, salt);
+      expectEvent(
+        await factory.cloneDeterministic(implementation, salt, '0x'),
+        'NewInstance',
+        { instance: predicted },
+      );
+    });
+  });
+});

+ 7 - 3
test/proxy/TransparentUpgradeableProxy.behaviour.js

@@ -1,6 +1,6 @@
 const { BN, expectRevert, expectEvent, constants } = require('@openzeppelin/test-helpers');
 const { ZERO_ADDRESS } = constants;
-const { toChecksumAddress, keccak256 } = require('ethereumjs-util');
+const ethereumjsUtil = require('ethereumjs-util');
 
 const { expect } = require('chai');
 
@@ -19,6 +19,10 @@ const ClashingImplementation = artifacts.require('ClashingImplementation');
 const IMPLEMENTATION_LABEL = 'eip1967.proxy.implementation';
 const ADMIN_LABEL = 'eip1967.proxy.admin';
 
+function toChecksumAddress (address) {
+  return ethereumjsUtil.toChecksumAddress('0x' + address.replace(/^0x/, '').padStart(40, '0'));
+}
+
 module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createProxy, accounts) {
   const [proxyAdminAddress, proxyAdminOwner, anotherAccount] = accounts;
 
@@ -308,13 +312,13 @@ module.exports = function shouldBehaveLikeTransparentUpgradeableProxy (createPro
 
   describe('storage', function () {
     it('should store the implementation address in specified location', async function () {
-      const slot = '0x' + new BN(keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16);
+      const slot = '0x' + new BN(ethereumjsUtil.keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16);
       const implementation = toChecksumAddress(await web3.eth.getStorageAt(this.proxyAddress, slot));
       expect(implementation).to.be.equal(this.implementationV0);
     });
 
     it('should store the admin proxy in specified location', async function () {
-      const slot = '0x' + new BN(keccak256(Buffer.from(ADMIN_LABEL))).subn(1).toString(16);
+      const slot = '0x' + new BN(ethereumjsUtil.keccak256(Buffer.from(ADMIN_LABEL))).subn(1).toString(16);
       const proxyAdmin = toChecksumAddress(await web3.eth.getStorageAt(this.proxyAddress, slot));
       expect(proxyAdmin).to.be.equal(proxyAdminAddress);
     });

+ 18 - 2
test/proxy/UpgradeableProxy.behaviour.js

@@ -1,5 +1,5 @@
 const { BN, expectRevert } = require('@openzeppelin/test-helpers');
-const { toChecksumAddress, keccak256 } = require('ethereumjs-util');
+const ethereumjsUtil = require('ethereumjs-util');
 
 const { expect } = require('chai');
 
@@ -7,6 +7,10 @@ const DummyImplementation = artifacts.require('DummyImplementation');
 
 const IMPLEMENTATION_LABEL = 'eip1967.proxy.implementation';
 
+function toChecksumAddress (address) {
+  return ethereumjsUtil.toChecksumAddress('0x' + address.replace(/^0x/, '').padStart(40, '0'));
+}
+
 module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAdminAddress, proxyCreator) {
   it('cannot be initialized with a non-contract address', async function () {
     const nonContractAddress = proxyCreator;
@@ -24,7 +28,7 @@ module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAd
 
   const assertProxyInitialization = function ({ value, balance }) {
     it('sets the implementation address', async function () {
-      const slot = '0x' + new BN(keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16);
+      const slot = '0x' + new BN(ethereumjsUtil.keccak256(Buffer.from(IMPLEMENTATION_LABEL))).subn(1).toString(16);
       const implementation = toChecksumAddress(await web3.eth.getStorageAt(this.proxy, slot));
       expect(implementation).to.be.equal(this.implementation);
     });
@@ -210,5 +214,17 @@ module.exports = function shouldBehaveLikeUpgradeableProxy (createProxy, proxyAd
         });
       });
     });
+
+    describe('reverting initialization', function () {
+      const initializeData = new DummyImplementation('').contract
+        .methods.reverts().encodeABI();
+
+      it('reverts', async function () {
+        await expectRevert(
+          createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator }),
+          'DummyImplementation reverted',
+        );
+      });
+    });
   });
 };

+ 1 - 1
test/token/ERC1155/ERC1155.behavior.js

@@ -106,7 +106,7 @@ function shouldBehaveLikeERC1155 ([minter, firstTokenHolder, secondTokenHolder,
             [firstTokenHolder, secondTokenHolder, ZERO_ADDRESS],
             [firstTokenId, secondTokenId, unknownTokenId],
           ),
-          'ERC1155: batch balance query for the zero address',
+          'ERC1155: balance query for the zero address',
         );
       });
 

+ 33 - 0
test/token/ERC777/ERC777.test.js

@@ -447,4 +447,37 @@ contract('ERC777', function (accounts) {
       expect(await this.token.defaultOperators()).to.deep.equal([]);
     });
   });
+
+  describe('relative order of hooks', function () {
+    beforeEach(async function () {
+      await singletons.ERC1820Registry(registryFunder);
+      this.sender = await ERC777SenderRecipientMock.new();
+      await this.sender.registerRecipient(this.sender.address);
+      await this.sender.registerSender(this.sender.address);
+      this.token = await ERC777.new(holder, initialSupply, name, symbol, []);
+      await this.token.send(this.sender.address, 1, '0x', { from: holder });
+    });
+
+    it('send', async function () {
+      const { receipt } = await this.sender.send(this.token.address, anyone, 1, '0x');
+
+      const internalBeforeHook = receipt.logs.findIndex(l => l.event === 'BeforeTokenTransfer');
+      expect(internalBeforeHook).to.be.gte(0);
+      const externalSendHook = receipt.logs.findIndex(l => l.event === 'TokensToSendCalled');
+      expect(externalSendHook).to.be.gte(0);
+
+      expect(externalSendHook).to.be.lt(internalBeforeHook);
+    });
+
+    it('burn', async function () {
+      const { receipt } = await this.sender.burn(this.token.address, 1, '0x');
+
+      const internalBeforeHook = receipt.logs.findIndex(l => l.event === 'BeforeTokenTransfer');
+      expect(internalBeforeHook).to.be.gte(0);
+      const externalSendHook = receipt.logs.findIndex(l => l.event === 'TokensToSendCalled');
+      expect(externalSendHook).to.be.gte(0);
+
+      expect(externalSendHook).to.be.lt(internalBeforeHook);
+    });
+  });
 });

+ 40 - 1
test/utils/EnumerableMap.test.js

@@ -1,4 +1,4 @@
-const { BN, expectEvent } = require('@openzeppelin/test-helpers');
+const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
 const { expect } = require('chai');
 
 const zip = require('lodash.zip');
@@ -139,4 +139,43 @@ contract('EnumerableMap', function (accounts) {
       expect(await this.map.contains(keyB)).to.equal(false);
     });
   });
+
+  describe('read', function () {
+    beforeEach(async function () {
+      await this.map.set(keyA, accountA);
+    });
+
+    describe('get', function () {
+      it('existing value', async function () {
+        expect(await this.map.get(keyA)).to.be.equal(accountA);
+      });
+      it('missing value', async function () {
+        await expectRevert(this.map.get(keyB), 'EnumerableMap: nonexistent key');
+      });
+    });
+
+    describe('get with message', function () {
+      it('existing value', async function () {
+        expect(await this.map.getWithMessage(keyA, 'custom error string')).to.be.equal(accountA);
+      });
+      it('missing value', async function () {
+        await expectRevert(this.map.getWithMessage(keyB, 'custom error string'), 'custom error string');
+      });
+    });
+
+    describe('tryGet', function () {
+      it('existing value', async function () {
+        expect(await this.map.tryGet(keyA)).to.be.deep.equal({
+          0: true,
+          1: accountA,
+        });
+      });
+      it('missing value', async function () {
+        expect(await this.map.tryGet(keyB)).to.be.deep.equal({
+          0: false,
+          1: constants.ZERO_ADDRESS,
+        });
+      });
+    });
+  });
 });

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff