diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b6c1349f5..5c88a5c0e0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,17 @@ * `ERC721`: remove enumerability of tokens from the base implementation. This feature is now provided separately through the `ERC721Enumerable` extension. ([#2511](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2511)) * `AccessControl`: removed enumerability by default for a more lightweight contract. It is now opt-in through `AccessControlEnumerable`. ([#2512](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2512)) * Meta Transactions: add `ERC2771Context` and a `MinimalForwarder` for meta-transactions. ([#2508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2508)) + * Overall reorganisation of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503)) + +### How to upgrade from 3.x + +Since this version has moved a few contracts to different directories, users upgrading from a previous version will need to adjust their import statements. To make this easier, the package includes a script that will migrate import statements automatically. After upgrading to the latest version of the package, run: + +``` +npx openzeppelin-contracts-migrate-imports +``` + +Make sure you're using git or another version control system to be able to recover from any potential error in our script. ## 3.4.0 (2021-02-02) diff --git a/contracts/access/AccessControlEnumerable.sol b/contracts/access/AccessControlEnumerable.sol index be58a7b8de8..b68ad1ad474 100644 --- a/contracts/access/AccessControlEnumerable.sol +++ b/contracts/access/AccessControlEnumerable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.0; import "./AccessControl.sol"; -import "../utils/EnumerableSet.sol"; +import "../utils/structs/EnumerableSet.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. diff --git a/contracts/access/README.adoc b/contracts/access/README.adoc index c1431c1200e..e59bba0fce1 100644 --- a/contracts/access/README.adoc +++ b/contracts/access/README.adoc @@ -7,7 +7,6 @@ This directory provides ways to restrict who can access the functions of a contr - {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. - {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. -- {TimelockController} is used in combination with one of the above two mechanisms. By assigning a role to an instance of the `TimelockController` contract, the access to the functions controlled by that role will be delayed by some amount of time. == Authorization @@ -16,88 +15,3 @@ This directory provides ways to restrict who can access the functions of a contr {{AccessControl}} {{AccessControlEnumerable}} - -== Timelock - -{{TimelockController}} - -[[timelock-terminology]] -==== Terminology - -* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content. -* *Operation status:* -** *Unset:* An operation that is not part of the timelock mechanism. -** *Pending:* An operation that has been scheduled, before the timer expires. -** *Ready:* An operation that has been scheduled, after the timer expires. -** *Done:* An operation that has been executed. -* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations. -* *Role*: -** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations. -** *Executor:* An address (smart contract or EOA) that is in charge of executing operations. - -[[timelock-operation]] -==== Operation structure - -Operation executed by the xref:api:access.adoc#TimelockController[`TimelockControler`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations. - -Both operations contain: - -* *Target*, the address of the smart contract that the timelock should operate on. -* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction. -* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encode using web3js as follows: - -```javascript -const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI() -``` - -* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency. -* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value. - -In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length. - -[[timelock-operation-lifecycle]] -==== Operation lifecycle - -Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle: - -`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done` - -* By calling xref:api:access.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:access.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:access.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method. -* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed. -* By calling xref:api:access.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:access.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed. -* xref:api:access.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled. - -Operations status can be queried using the functions: - -* xref:api:access.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`] -* xref:api:access.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`] -* xref:api:access.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`] - -[[timelock-roles]] -==== Roles - -[[timelock-admin]] -===== Admin - -The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, both the timelock and the deployer have this role. After further configuration and testing, the deployer can renounce this role such that all further maintenance operations have to go through the timelock process. - -This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5` - -[[timelock-proposer]] -===== Proposer - -The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO. - -WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers. - -This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1` - -[[timelock-executor]] -===== Executor - -The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executor can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers. - -This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63` - - -WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management. diff --git a/contracts/cryptography/README.adoc b/contracts/cryptography/README.adoc deleted file mode 100644 index 05e16ec91f8..00000000000 --- a/contracts/cryptography/README.adoc +++ /dev/null @@ -1,16 +0,0 @@ -= Cryptography - -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/cryptography - -This collection of libraries provides simple and safe ways to use different cryptographic primitives. - -The following related EIPs are in draft status and can be found in the drafts directory. - -- {EIP712} - -== Libraries - -{{ECDSA}} - -{{MerkleProof}} diff --git a/contracts/drafts/README.adoc b/contracts/drafts/README.adoc deleted file mode 100644 index 3efcef91d61..00000000000 --- a/contracts/drafts/README.adoc +++ /dev/null @@ -1,15 +0,0 @@ -= Draft EIPs - -This directory contains implementations of EIPs that are still in Draft status. - -Due to their nature as drafts, the details of these contracts may change and we cannot guarantee their xref:ROOT:releases-stability.adoc[stability]. Minor releases of OpenZeppelin Contracts may contain breaking changes for the contracts in this directory, which will be duly announced in the https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md[changelog]. The EIPs included here are used by projects in production and this may make them less likely to change significantly. - -== Cryptography - -{{EIP712}} - -== ERC 20 - -{{IERC20Permit}} - -{{ERC20Permit}} diff --git a/contracts/governance/README.adoc b/contracts/governance/README.adoc new file mode 100644 index 00000000000..4dc967f8efa --- /dev/null +++ b/contracts/governance/README.adoc @@ -0,0 +1,91 @@ += Governance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access + +This directory includes primitives for on-chain governance. We currently only offer the {TimelockController} contract, that can be used as a component in a governance systems to introduce a delay between a proposal and its execution. + +== Timelock + +{{TimelockController}} + +[[timelock-terminology]] +==== Terminology + +* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content. +* *Operation status:* +** *Unset:* An operation that is not part of the timelock mechanism. +** *Pending:* An operation that has been scheduled, before the timer expires. +** *Ready:* An operation that has been scheduled, after the timer expires. +** *Done:* An operation that has been executed. +* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations. +* *Role*: +** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations. +** *Executor:* An address (smart contract or EOA) that is in charge of executing operations. + +[[timelock-operation]] +==== Operation structure + +Operation executed by the xref:api:access.adoc#TimelockController[`TimelockControler`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations. + +Both operations contain: + +* *Target*, the address of the smart contract that the timelock should operate on. +* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction. +* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encode using web3js as follows: + +```javascript +const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI() +``` + +* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency. +* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value. + +In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length. + +[[timelock-operation-lifecycle]] +==== Operation lifecycle + +Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle: + +`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done` + +* By calling xref:api:access.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:access.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:access.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method. +* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed. +* By calling xref:api:access.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:access.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed. +* xref:api:access.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled. + +Operations status can be queried using the functions: + +* xref:api:access.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`] +* xref:api:access.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`] +* xref:api:access.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`] + +[[timelock-roles]] +==== Roles + +[[timelock-admin]] +===== Admin + +The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, both the timelock and the deployer have this role. After further configuration and testing, the deployer can renounce this role such that all further maintenance operations have to go through the timelock process. + +This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5` + +[[timelock-proposer]] +===== Proposer + +The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO. + +WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers. + +This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1` + +[[timelock-executor]] +===== Executor + +The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executor can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers. + +This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63` + + +WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management. diff --git a/contracts/access/TimelockController.sol b/contracts/governance/TimelockController.sol similarity index 99% rename from contracts/access/TimelockController.sol rename to contracts/governance/TimelockController.sol index cba9b689580..a39cef0089e 100644 --- a/contracts/access/TimelockController.sol +++ b/contracts/governance/TimelockController.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./AccessControl.sol"; +import "../access/AccessControl.sol"; /** * @dev Contract module which acts as a timelocked controller. When set as the diff --git a/contracts/introspection/README.adoc b/contracts/introspection/README.adoc deleted file mode 100644 index 0668de417e2..00000000000 --- a/contracts/introspection/README.adoc +++ /dev/null @@ -1,33 +0,0 @@ -= Introspection - -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/introspection - -This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[type introspection] of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_. - -Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors. - -There are two main ways to approach this. - -* Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`. -* Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts. - -Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security. - -== Local - -{{IERC165}} - -{{ERC165}} - -{{ERC165Storage}} - -{{ERC165Checker}} - -== Global - -{{IERC1820Registry}} - -{{IERC1820Implementer}} - -{{ERC1820Implementer}} diff --git a/contracts/math/README.adoc b/contracts/math/README.adoc deleted file mode 100644 index b03d441bae3..00000000000 --- a/contracts/math/README.adoc +++ /dev/null @@ -1,14 +0,0 @@ -= Math - -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/math - -These are math-related utilities. - -== Libraries - -{{SafeMath}} - -{{SignedSafeMath}} - -{{Math}} diff --git a/contracts/metatx/MinimalForwarder.sol b/contracts/metatx/MinimalForwarder.sol index 6c028ec049a..ee1e1523fbe 100644 --- a/contracts/metatx/MinimalForwarder.sol +++ b/contracts/metatx/MinimalForwarder.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "../cryptography/ECDSA.sol"; -import "../drafts/EIP712.sol"; +import "../utils/cryptography/ECDSA.sol"; +import "../utils/cryptography/draft-EIP712.sol"; /* * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}. diff --git a/contracts/metatx/README.adoc b/contracts/metatx/README.adoc index 51a97913fa4..eccdeaf9740 100644 --- a/contracts/metatx/README.adoc +++ b/contracts/metatx/README.adoc @@ -1,7 +1,7 @@ = Meta Transactions [.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/math +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx == Core diff --git a/contracts/mocks/ConditionalEscrowMock.sol b/contracts/mocks/ConditionalEscrowMock.sol index 5ceea176145..ececf0521d5 100644 --- a/contracts/mocks/ConditionalEscrowMock.sol +++ b/contracts/mocks/ConditionalEscrowMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../payment/escrow/ConditionalEscrow.sol"; +import "../utils/escrow/ConditionalEscrow.sol"; // mock class using ConditionalEscrow contract ConditionalEscrowMock is ConditionalEscrow { diff --git a/contracts/mocks/Create2Impl.sol b/contracts/mocks/Create2Impl.sol index 7e5cd1a1c04..b062717391c 100644 --- a/contracts/mocks/Create2Impl.sol +++ b/contracts/mocks/Create2Impl.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.0; import "../utils/Create2.sol"; -import "../introspection/ERC1820Implementer.sol"; +import "../utils/introspection/ERC1820Implementer.sol"; contract Create2Impl { function deploy(uint256 value, bytes32 salt, bytes memory code) public { diff --git a/contracts/mocks/ECDSAMock.sol b/contracts/mocks/ECDSAMock.sol index beec44d2603..99f6a7983e0 100644 --- a/contracts/mocks/ECDSAMock.sol +++ b/contracts/mocks/ECDSAMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../cryptography/ECDSA.sol"; +import "../utils/cryptography/ECDSA.sol"; contract ECDSAMock { using ECDSA for bytes32; diff --git a/contracts/mocks/EIP712External.sol b/contracts/mocks/EIP712External.sol index 7c37fb3c94d..943556f2533 100644 --- a/contracts/mocks/EIP712External.sol +++ b/contracts/mocks/EIP712External.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "../drafts/EIP712.sol"; -import "../cryptography/ECDSA.sol"; +import "../utils/cryptography/draft-EIP712.sol"; +import "../utils/cryptography/ECDSA.sol"; contract EIP712External is EIP712 { constructor(string memory name, string memory version) EIP712(name, version) {} diff --git a/contracts/mocks/ERC1155BurnableMock.sol b/contracts/mocks/ERC1155BurnableMock.sol index 24ea6121ce1..8485eecfa59 100644 --- a/contracts/mocks/ERC1155BurnableMock.sol +++ b/contracts/mocks/ERC1155BurnableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../token/ERC1155/ERC1155Burnable.sol"; +import "../token/ERC1155/extensions/ERC1155Burnable.sol"; contract ERC1155BurnableMock is ERC1155Burnable { constructor(string memory uri) ERC1155(uri) { } diff --git a/contracts/mocks/ERC1155PausableMock.sol b/contracts/mocks/ERC1155PausableMock.sol index 4f7edcccbc3..c4e4dd7beed 100644 --- a/contracts/mocks/ERC1155PausableMock.sol +++ b/contracts/mocks/ERC1155PausableMock.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.0; import "./ERC1155Mock.sol"; -import "../token/ERC1155/ERC1155Pausable.sol"; +import "../token/ERC1155/extensions/ERC1155Pausable.sol"; contract ERC1155PausableMock is ERC1155Mock, ERC1155Pausable { constructor(string memory uri) ERC1155Mock(uri) { } diff --git a/contracts/mocks/ERC1155ReceiverMock.sol b/contracts/mocks/ERC1155ReceiverMock.sol index c3a60d6b94b..a8babdc0d63 100644 --- a/contracts/mocks/ERC1155ReceiverMock.sol +++ b/contracts/mocks/ERC1155ReceiverMock.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "../introspection/ERC165.sol"; import "../token/ERC1155/IERC1155Receiver.sol"; +import "../utils/introspection/ERC165.sol"; contract ERC1155ReceiverMock is IERC1155Receiver, ERC165 { bytes4 private _recRetval; diff --git a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol index ffe8965bb2f..ecc4579d9c1 100644 --- a/contracts/mocks/ERC165/ERC165InterfacesSupported.sol +++ b/contracts/mocks/ERC165/ERC165InterfacesSupported.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../../introspection/IERC165.sol"; +import "../../utils/introspection/IERC165.sol"; /** * https://eips.ethereum.org/EIPS/eip-214#specification diff --git a/contracts/mocks/ERC165CheckerMock.sol b/contracts/mocks/ERC165CheckerMock.sol index a05f0f53591..bda5cfc78c2 100644 --- a/contracts/mocks/ERC165CheckerMock.sol +++ b/contracts/mocks/ERC165CheckerMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../introspection/ERC165Checker.sol"; +import "../utils/introspection/ERC165Checker.sol"; contract ERC165CheckerMock { using ERC165Checker for address; diff --git a/contracts/mocks/ERC165Mock.sol b/contracts/mocks/ERC165Mock.sol index 5f9ff3f69a8..ee5e540a170 100644 --- a/contracts/mocks/ERC165Mock.sol +++ b/contracts/mocks/ERC165Mock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../introspection/ERC165.sol"; +import "../utils/introspection/ERC165.sol"; contract ERC165Mock is ERC165 { } diff --git a/contracts/mocks/ERC165StorageMock.sol b/contracts/mocks/ERC165StorageMock.sol index 36262d37d3c..4b0bae90865 100644 --- a/contracts/mocks/ERC165StorageMock.sol +++ b/contracts/mocks/ERC165StorageMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../introspection/ERC165Storage.sol"; +import "../utils/introspection/ERC165Storage.sol"; contract ERC165StorageMock is ERC165Storage { function registerInterface(bytes4 interfaceId) public { diff --git a/contracts/mocks/ERC1820ImplementerMock.sol b/contracts/mocks/ERC1820ImplementerMock.sol index 126d8671d74..a6012d7ffee 100644 --- a/contracts/mocks/ERC1820ImplementerMock.sol +++ b/contracts/mocks/ERC1820ImplementerMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../introspection/ERC1820Implementer.sol"; +import "../utils/introspection/ERC1820Implementer.sol"; contract ERC1820ImplementerMock is ERC1820Implementer { function registerInterfaceForAddress(bytes32 interfaceHash, address account) public { diff --git a/contracts/mocks/ERC20BurnableMock.sol b/contracts/mocks/ERC20BurnableMock.sol index e4bd44cfadd..72d4e0b1681 100644 --- a/contracts/mocks/ERC20BurnableMock.sol +++ b/contracts/mocks/ERC20BurnableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../token/ERC20/ERC20Burnable.sol"; +import "../token/ERC20/extensions/ERC20Burnable.sol"; contract ERC20BurnableMock is ERC20Burnable { constructor ( diff --git a/contracts/mocks/ERC20CappedMock.sol b/contracts/mocks/ERC20CappedMock.sol index 6cf74e9a39f..e5e3feb5f08 100644 --- a/contracts/mocks/ERC20CappedMock.sol +++ b/contracts/mocks/ERC20CappedMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../token/ERC20/ERC20Capped.sol"; +import "../token/ERC20/extensions/ERC20Capped.sol"; contract ERC20CappedMock is ERC20Capped { constructor (string memory name, string memory symbol, uint256 cap) diff --git a/contracts/mocks/ERC20PausableMock.sol b/contracts/mocks/ERC20PausableMock.sol index 0433e49a82a..6e61800df4b 100644 --- a/contracts/mocks/ERC20PausableMock.sol +++ b/contracts/mocks/ERC20PausableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../token/ERC20/ERC20Pausable.sol"; +import "../token/ERC20/extensions/ERC20Pausable.sol"; // mock class using ERC20Pausable contract ERC20PausableMock is ERC20Pausable { diff --git a/contracts/mocks/ERC20PermitMock.sol b/contracts/mocks/ERC20PermitMock.sol index 6699cfe7cda..e9f2daf5e6b 100644 --- a/contracts/mocks/ERC20PermitMock.sol +++ b/contracts/mocks/ERC20PermitMock.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.0; -import "../drafts/ERC20Permit.sol"; + +import "../token/ERC20/extensions/draft-ERC20Permit.sol"; contract ERC20PermitMock is ERC20Permit { constructor ( diff --git a/contracts/mocks/ERC20SnapshotMock.sol b/contracts/mocks/ERC20SnapshotMock.sol index d8db876a01b..792bee1997b 100644 --- a/contracts/mocks/ERC20SnapshotMock.sol +++ b/contracts/mocks/ERC20SnapshotMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../token/ERC20/ERC20Snapshot.sol"; +import "../token/ERC20/extensions/ERC20Snapshot.sol"; contract ERC20SnapshotMock is ERC20Snapshot { diff --git a/contracts/mocks/ERC721BurnableMock.sol b/contracts/mocks/ERC721BurnableMock.sol index d2531b93c37..a1a5893c512 100644 --- a/contracts/mocks/ERC721BurnableMock.sol +++ b/contracts/mocks/ERC721BurnableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../token/ERC721/ERC721Burnable.sol"; +import "../token/ERC721/extensions/ERC721Burnable.sol"; contract ERC721BurnableMock is ERC721Burnable { constructor(string memory name, string memory symbol) ERC721(name, symbol) { } diff --git a/contracts/mocks/ERC721EnumerableMock.sol b/contracts/mocks/ERC721EnumerableMock.sol index 5dbc4cd133c..8ec0cddb2ec 100644 --- a/contracts/mocks/ERC721EnumerableMock.sol +++ b/contracts/mocks/ERC721EnumerableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../token/ERC721/ERC721Enumerable.sol"; +import "../token/ERC721/extensions/ERC721Enumerable.sol"; /** * @title ERC721Mock diff --git a/contracts/mocks/ERC721PausableMock.sol b/contracts/mocks/ERC721PausableMock.sol index 6bebea4a4f4..2133341aaf6 100644 --- a/contracts/mocks/ERC721PausableMock.sol +++ b/contracts/mocks/ERC721PausableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../token/ERC721/ERC721Pausable.sol"; +import "../token/ERC721/extensions/ERC721Pausable.sol"; /** * @title ERC721PausableMock diff --git a/contracts/mocks/ERC777SenderRecipientMock.sol b/contracts/mocks/ERC777SenderRecipientMock.sol index 9d9cff3f3e1..3a92d999c36 100644 --- a/contracts/mocks/ERC777SenderRecipientMock.sol +++ b/contracts/mocks/ERC777SenderRecipientMock.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.0; -import "../utils/Context.sol"; import "../token/ERC777/IERC777.sol"; import "../token/ERC777/IERC777Sender.sol"; import "../token/ERC777/IERC777Recipient.sol"; -import "../introspection/IERC1820Registry.sol"; -import "../introspection/ERC1820Implementer.sol"; +import "../utils/Context.sol"; +import "../utils/introspection/IERC1820Registry.sol"; +import "../utils/introspection/ERC1820Implementer.sol"; contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer { event TokensToSendCalled( @@ -150,4 +150,3 @@ contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, token.burn(amount, data); } } - diff --git a/contracts/mocks/EnumerableMapMock.sol b/contracts/mocks/EnumerableMapMock.sol index ea32f975b80..bacbf6743e6 100644 --- a/contracts/mocks/EnumerableMapMock.sol +++ b/contracts/mocks/EnumerableMapMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../utils/EnumerableMap.sol"; +import "../utils/structs/EnumerableMap.sol"; contract EnumerableMapMock { using EnumerableMap for EnumerableMap.UintToAddressMap; diff --git a/contracts/mocks/EnumerableSetMock.sol b/contracts/mocks/EnumerableSetMock.sol index eb5aa4f6fc5..26f6f60c21f 100644 --- a/contracts/mocks/EnumerableSetMock.sol +++ b/contracts/mocks/EnumerableSetMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../utils/EnumerableSet.sol"; +import "../utils/structs/EnumerableSet.sol"; // Bytes32Set contract EnumerableBytes32SetMock { diff --git a/contracts/mocks/InitializableMock.sol b/contracts/mocks/InitializableMock.sol index aacb30b208a..8f313ed5462 100644 --- a/contracts/mocks/InitializableMock.sol +++ b/contracts/mocks/InitializableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../proxy/Initializable.sol"; +import "../utils/Initializable.sol"; /** * @title InitializableMock diff --git a/contracts/mocks/MathMock.sol b/contracts/mocks/MathMock.sol index 3f20efa0192..34bf6b6d400 100644 --- a/contracts/mocks/MathMock.sol +++ b/contracts/mocks/MathMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../math/Math.sol"; +import "../utils/math/Math.sol"; contract MathMock { function max(uint256 a, uint256 b) public pure returns (uint256) { diff --git a/contracts/mocks/MerkleProofWrapper.sol b/contracts/mocks/MerkleProofWrapper.sol index 004287e1079..bf1c6e4dff1 100644 --- a/contracts/mocks/MerkleProofWrapper.sol +++ b/contracts/mocks/MerkleProofWrapper.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import { MerkleProof } from "../cryptography/MerkleProof.sol"; +import "../utils/cryptography/MerkleProof.sol"; contract MerkleProofWrapper { function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) public pure returns (bool) { diff --git a/contracts/mocks/MultipleInheritanceInitializableMocks.sol b/contracts/mocks/MultipleInheritanceInitializableMocks.sol index f0095ce9662..81f340a4e38 100644 --- a/contracts/mocks/MultipleInheritanceInitializableMocks.sol +++ b/contracts/mocks/MultipleInheritanceInitializableMocks.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.0; -import "../proxy/Initializable.sol"; +import "../utils/Initializable.sol"; // Sample contracts showing upgradeability with multiple inheritance. // Child contract inherits from Father and Mother contracts, and Father extends from Gramps. -// +// // Human // / \ // | Gramps diff --git a/contracts/mocks/PausableMock.sol b/contracts/mocks/PausableMock.sol index fb8a1b81fa1..eebc2be4a39 100644 --- a/contracts/mocks/PausableMock.sol +++ b/contracts/mocks/PausableMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../utils/Pausable.sol"; +import "../security/Pausable.sol"; contract PausableMock is Pausable { bool public drasticMeasureTaken; diff --git a/contracts/mocks/PullPaymentMock.sol b/contracts/mocks/PullPaymentMock.sol index b9c6ea37faa..929659da6a3 100644 --- a/contracts/mocks/PullPaymentMock.sol +++ b/contracts/mocks/PullPaymentMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../payment/PullPayment.sol"; +import "../security/PullPayment.sol"; // mock class using PullPayment contract PullPaymentMock is PullPayment { diff --git a/contracts/mocks/ReentrancyMock.sol b/contracts/mocks/ReentrancyMock.sol index 0333e9059b0..c561dbbb9d5 100644 --- a/contracts/mocks/ReentrancyMock.sol +++ b/contracts/mocks/ReentrancyMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../utils/ReentrancyGuard.sol"; +import "../security/ReentrancyGuard.sol"; import "./ReentrancyAttack.sol"; contract ReentrancyMock is ReentrancyGuard { diff --git a/contracts/mocks/RegressionImplementation.sol b/contracts/mocks/RegressionImplementation.sol index e11826f211f..c53fc3c4e36 100644 --- a/contracts/mocks/RegressionImplementation.sol +++ b/contracts/mocks/RegressionImplementation.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../proxy/Initializable.sol"; +import "../utils/Initializable.sol"; contract Implementation1 is Initializable { uint internal _value; diff --git a/contracts/mocks/SafeCastMock.sol b/contracts/mocks/SafeCastMock.sol index 5d8e6b0fbc9..9baf9dd2090 100644 --- a/contracts/mocks/SafeCastMock.sol +++ b/contracts/mocks/SafeCastMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../utils/SafeCast.sol"; +import "../utils/math/SafeCast.sol"; contract SafeCastMock { using SafeCast for uint; diff --git a/contracts/mocks/SafeERC20Helper.sol b/contracts/mocks/SafeERC20Helper.sol index 7d347bbda97..d51c38de7f6 100644 --- a/contracts/mocks/SafeERC20Helper.sol +++ b/contracts/mocks/SafeERC20Helper.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import "../utils/Context.sol"; import "../token/ERC20/IERC20.sol"; -import "../token/ERC20/SafeERC20.sol"; +import "../token/ERC20/utils/SafeERC20.sol"; contract ERC20ReturnFalseMock is Context { uint256 private _allowance; diff --git a/contracts/mocks/SafeMathMock.sol b/contracts/mocks/SafeMathMock.sol index 2aacf11fbea..7158cf7406e 100644 --- a/contracts/mocks/SafeMathMock.sol +++ b/contracts/mocks/SafeMathMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../math/SafeMath.sol"; +import "../utils/math/SafeMath.sol"; contract SafeMathMock { function tryAdd(uint256 a, uint256 b) public pure returns (bool flag, uint256 value) { diff --git a/contracts/mocks/SignedSafeMathMock.sol b/contracts/mocks/SignedSafeMathMock.sol index 08afdc66b01..8d10217985e 100644 --- a/contracts/mocks/SignedSafeMathMock.sol +++ b/contracts/mocks/SignedSafeMathMock.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../math/SignedSafeMath.sol"; +import "../utils/math/SignedSafeMath.sol"; contract SignedSafeMathMock { function mul(int256 a, int256 b) public pure returns (int256) { diff --git a/contracts/mocks/SingleInheritanceInitializableMocks.sol b/contracts/mocks/SingleInheritanceInitializableMocks.sol index f5f81a7b0a2..2c9b75ee4f8 100644 --- a/contracts/mocks/SingleInheritanceInitializableMocks.sol +++ b/contracts/mocks/SingleInheritanceInitializableMocks.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../proxy/Initializable.sol"; +import "../utils/Initializable.sol"; /** * @title MigratableMockV1 diff --git a/contracts/payment/README.adoc b/contracts/payment/README.adoc deleted file mode 100644 index 7d6151d9067..00000000000 --- a/contracts/payment/README.adoc +++ /dev/null @@ -1,22 +0,0 @@ -= Payment - -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/payment - -Utilities related to sending and receiving payments. Examples are {PullPayment}, which implements the best security practices when sending funds to third parties, and {PaymentSplitter} to receive incoming payments among a number of beneficiaries. - -TIP: When transferring funds to and from untrusted third parties, there is always a security risk of reentrancy. If you would like to learn more about this and ways to protect against it, check out our blog post https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. - -== Utilities - -{{PaymentSplitter}} - -{{PullPayment}} - -== Escrow - -{{Escrow}} - -{{ConditionalEscrow}} - -{{RefundEscrow}} diff --git a/contracts/presets/README.adoc b/contracts/presets/README.adoc deleted file mode 100644 index 8f189857639..00000000000 --- a/contracts/presets/README.adoc +++ /dev/null @@ -1,22 +0,0 @@ -= Presets - -[.readme-notice] -NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/presets - -These contracts integrate different Ethereum standards (ERCs) with custom extensions and modules, showcasing common configurations that are ready to deploy **without having to write any Solidity code**. - -They can be used as-is for quick prototyping and testing, but are **also suitable for production environments**. - -TIP: Intermediate and advanced users can use these as starting points when writing their own contracts, extending them with custom functionality as they see fit. - -== Tokens - -{{ERC20PresetMinterPauser}} - -{{ERC721PresetMinterPauserAutoId}} - -{{ERC1155PresetMinterPauser}} - -{{ERC20PresetFixedSupply}} - -{{ERC777PresetFixedSupply}} diff --git a/contracts/proxy/README.adoc b/contracts/proxy/README.adoc index 452ad91333f..ea6bf3a389d 100644 --- a/contracts/proxy/README.adoc +++ b/contracts/proxy/README.adoc @@ -21,8 +21,12 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th {{UpgradeableProxy}} +== Transparent Proxy + {{TransparentUpgradeableProxy}} +{{ProxyAdmin}} + == Beacon {{BeaconProxy}} @@ -34,9 +38,3 @@ CAUTION: Using upgradeable proxies correctly and securely is a difficult task th == Minimal Clones {{Clones}} - -== Utilities - -{{Initializable}} - -{{ProxyAdmin}} diff --git a/contracts/proxy/BeaconProxy.sol b/contracts/proxy/beacon/BeaconProxy.sol similarity index 98% rename from contracts/proxy/BeaconProxy.sol rename to contracts/proxy/beacon/BeaconProxy.sol index fa9c1af3190..a453c6248e7 100644 --- a/contracts/proxy/BeaconProxy.sol +++ b/contracts/proxy/beacon/BeaconProxy.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.0; -import "./Proxy.sol"; -import "../utils/Address.sol"; import "./IBeacon.sol"; +import "../Proxy.sol"; +import "../../utils/Address.sol"; /** * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}. diff --git a/contracts/proxy/IBeacon.sol b/contracts/proxy/beacon/IBeacon.sol similarity index 100% rename from contracts/proxy/IBeacon.sol rename to contracts/proxy/beacon/IBeacon.sol diff --git a/contracts/proxy/UpgradeableBeacon.sol b/contracts/proxy/beacon/UpgradeableBeacon.sol similarity index 96% rename from contracts/proxy/UpgradeableBeacon.sol rename to contracts/proxy/beacon/UpgradeableBeacon.sol index c9dc07ddc2c..aac40d00958 100644 --- a/contracts/proxy/UpgradeableBeacon.sol +++ b/contracts/proxy/beacon/UpgradeableBeacon.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.0; import "./IBeacon.sol"; -import "../access/Ownable.sol"; -import "../utils/Address.sol"; +import "../../access/Ownable.sol"; +import "../../utils/Address.sol"; /** * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their diff --git a/contracts/proxy/ProxyAdmin.sol b/contracts/proxy/transparent/ProxyAdmin.sol similarity index 98% rename from contracts/proxy/ProxyAdmin.sol rename to contracts/proxy/transparent/ProxyAdmin.sol index 4ee2124ce03..f68c9ae0422 100644 --- a/contracts/proxy/ProxyAdmin.sol +++ b/contracts/proxy/transparent/ProxyAdmin.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "../access/Ownable.sol"; import "./TransparentUpgradeableProxy.sol"; +import "../../access/Ownable.sol"; /** * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an diff --git a/contracts/proxy/TransparentUpgradeableProxy.sol b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol similarity index 99% rename from contracts/proxy/TransparentUpgradeableProxy.sol rename to contracts/proxy/transparent/TransparentUpgradeableProxy.sol index 3ef2d26b664..4ce4eec36d5 100644 --- a/contracts/proxy/TransparentUpgradeableProxy.sol +++ b/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./UpgradeableProxy.sol"; +import "../UpgradeableProxy.sol"; /** * @dev This contract implements a proxy that is upgradeable by an admin. diff --git a/contracts/utils/Pausable.sol b/contracts/security/Pausable.sol similarity index 98% rename from contracts/utils/Pausable.sol rename to contracts/security/Pausable.sol index 9a56f3293ae..dd0db6e6bf1 100644 --- a/contracts/utils/Pausable.sol +++ b/contracts/security/Pausable.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./Context.sol"; +import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop diff --git a/contracts/payment/PullPayment.sol b/contracts/security/PullPayment.sol similarity index 98% rename from contracts/payment/PullPayment.sol rename to contracts/security/PullPayment.sol index cc68f2ac319..5170d6a7a21 100644 --- a/contracts/payment/PullPayment.sol +++ b/contracts/security/PullPayment.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./escrow/Escrow.sol"; +import "../utils/escrow/Escrow.sol"; /** * @dev Simple implementation of a diff --git a/contracts/security/README.adoc b/contracts/security/README.adoc new file mode 100644 index 00000000000..66f398fece5 --- /dev/null +++ b/contracts/security/README.adoc @@ -0,0 +1,20 @@ += Security + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/security + +These contracts aim to cover common security practices. + +* {PullPayment}: A pattern that can be used to avoid reentrancy attacks. +* {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions. +* {Pausable}: A common emergency response mechanism that can pause functionality while a remediation is pending. + +TIP: For an overview on reentrancy and the possible mechanisms to prevent it, read our article https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + +== Contracts + +{{PullPayment}} + +{{ReentrancyGuard}} + +{{Pausable}} diff --git a/contracts/utils/ReentrancyGuard.sol b/contracts/security/ReentrancyGuard.sol similarity index 100% rename from contracts/utils/ReentrancyGuard.sol rename to contracts/security/ReentrancyGuard.sol diff --git a/contracts/token/ERC1155/ERC1155.sol b/contracts/token/ERC1155/ERC1155.sol index a618f0da024..90746a24f00 100644 --- a/contracts/token/ERC1155/ERC1155.sol +++ b/contracts/token/ERC1155/ERC1155.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.0; import "./IERC1155.sol"; -import "./IERC1155MetadataURI.sol"; import "./IERC1155Receiver.sol"; -import "../../utils/Context.sol"; -import "../../introspection/ERC165.sol"; +import "./extensions/IERC1155MetadataURI.sol"; import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/introspection/ERC165.sol"; /** * diff --git a/contracts/token/ERC1155/IERC1155.sol b/contracts/token/ERC1155/IERC1155.sol index 6731963327f..6335adf7a80 100644 --- a/contracts/token/ERC1155/IERC1155.sol +++ b/contracts/token/ERC1155/IERC1155.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../../introspection/IERC165.sol"; +import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the diff --git a/contracts/token/ERC1155/IERC1155Receiver.sol b/contracts/token/ERC1155/IERC1155Receiver.sol index 07c441e22a4..ffd61dabc0f 100644 --- a/contracts/token/ERC1155/IERC1155Receiver.sol +++ b/contracts/token/ERC1155/IERC1155Receiver.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../../introspection/IERC165.sol"; +import "../../utils/introspection/IERC165.sol"; /** * _Available since v3.1._ diff --git a/contracts/token/ERC1155/README.adoc b/contracts/token/ERC1155/README.adoc index e804746957a..c1dc83e155e 100644 --- a/contracts/token/ERC1155/README.adoc +++ b/contracts/token/ERC1155/README.adoc @@ -32,6 +32,12 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel {{ERC1155Burnable}} -== Convenience +== Presets + +These contracts are preconfigured combinations of the above features. They can be used through inheritance or as models to copy and paste their source code. + +{{ERC1155PresetMinterPauser}} + +== Utilities {{ERC1155Holder}} diff --git a/contracts/token/ERC1155/ERC1155Burnable.sol b/contracts/token/ERC1155/extensions/ERC1155Burnable.sol similarity index 97% rename from contracts/token/ERC1155/ERC1155Burnable.sol rename to contracts/token/ERC1155/extensions/ERC1155Burnable.sol index d95b4385340..ddf9dd479a5 100644 --- a/contracts/token/ERC1155/ERC1155Burnable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Burnable.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./ERC1155.sol"; +import "../ERC1155.sol"; /** * @dev Extension of {ERC1155} that allows token holders to destroy both their diff --git a/contracts/token/ERC1155/ERC1155Pausable.sol b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol similarity index 93% rename from contracts/token/ERC1155/ERC1155Pausable.sol rename to contracts/token/ERC1155/extensions/ERC1155Pausable.sol index 934896b2c82..abfae3cfe69 100644 --- a/contracts/token/ERC1155/ERC1155Pausable.sol +++ b/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "./ERC1155.sol"; -import "../../utils/Pausable.sol"; +import "../ERC1155.sol"; +import "../../../security/Pausable.sol"; /** * @dev ERC1155 token with pausable token transfers, minting and burning. diff --git a/contracts/token/ERC1155/IERC1155MetadataURI.sol b/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol similarity index 95% rename from contracts/token/ERC1155/IERC1155MetadataURI.sol rename to contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol index f636cc2d87a..df55d97bb11 100644 --- a/contracts/token/ERC1155/IERC1155MetadataURI.sol +++ b/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./IERC1155.sol"; +import "../IERC1155.sol"; /** * @dev Interface of the optional ERC1155MetadataExtension interface, as defined diff --git a/contracts/presets/ERC1155PresetMinterPauser.sol b/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol similarity index 93% rename from contracts/presets/ERC1155PresetMinterPauser.sol rename to contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol index e8423f8b4ca..55e62c555be 100644 --- a/contracts/presets/ERC1155PresetMinterPauser.sol +++ b/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.0; -import "../access/AccessControlEnumerable.sol"; -import "../utils/Context.sol"; -import "../token/ERC1155/ERC1155.sol"; -import "../token/ERC1155/ERC1155Burnable.sol"; -import "../token/ERC1155/ERC1155Pausable.sol"; +import "../ERC1155.sol"; +import "../extensions/ERC1155Burnable.sol"; +import "../extensions/ERC1155Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; /** * @dev {ERC1155} token, including: diff --git a/contracts/token/ERC1155/ERC1155Holder.sol b/contracts/token/ERC1155/utils/ERC1155Holder.sol similarity index 100% rename from contracts/token/ERC1155/ERC1155Holder.sol rename to contracts/token/ERC1155/utils/ERC1155Holder.sol diff --git a/contracts/token/ERC1155/ERC1155Receiver.sol b/contracts/token/ERC1155/utils/ERC1155Receiver.sol similarity index 84% rename from contracts/token/ERC1155/ERC1155Receiver.sol rename to contracts/token/ERC1155/utils/ERC1155Receiver.sol index 0e2d6eecdae..aca156b06c6 100644 --- a/contracts/token/ERC1155/ERC1155Receiver.sol +++ b/contracts/token/ERC1155/utils/ERC1155Receiver.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "./IERC1155Receiver.sol"; -import "../../introspection/ERC165.sol"; +import "../IERC1155Receiver.sol"; +import "../../../utils/introspection/ERC165.sol"; /** * @dev _Available since v3.1._ diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index 188a834da27..c92df85a10e 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "../../utils/Context.sol"; import "./IERC20.sol"; +import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. diff --git a/contracts/token/ERC20/README.adoc b/contracts/token/ERC20/README.adoc index 60ecb4dfcd5..b8bfb00ca62 100644 --- a/contracts/token/ERC20/README.adoc +++ b/contracts/token/ERC20/README.adoc @@ -48,6 +48,22 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel {{ERC20Capped}} +== Draft EIPs + +The following EIPs are still in Draft status. Due to their nature as drafts, the details of these contracts may change and we cannot guarantee their xref:ROOT:releases-stability.adoc[stability]. Minor releases of OpenZeppelin Contracts may contain breaking changes for the contracts in this directory, which will be duly announced in the https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md[changelog]. The EIPs included here are used by projects in production and this may make them less likely to change significantly. + +{{IERC20Permit}} + +{{ERC20Permit}} + +== Presets + +These contracts are preconfigured combinations of the above features. They can be used through inheritance or as models to copy and paste their source code. + +{{ERC20PresetMinterPauser}} + +{{ERC20PresetFixedSupply}} + == Utilities {{SafeERC20}} diff --git a/contracts/token/ERC20/ERC20Burnable.sol b/contracts/token/ERC20/extensions/ERC20Burnable.sol similarity index 95% rename from contracts/token/ERC20/ERC20Burnable.sol rename to contracts/token/ERC20/extensions/ERC20Burnable.sol index 7bdff6fa246..2335742ad9e 100644 --- a/contracts/token/ERC20/ERC20Burnable.sol +++ b/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "../../utils/Context.sol"; -import "./ERC20.sol"; +import "../ERC20.sol"; +import "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own diff --git a/contracts/token/ERC20/ERC20Capped.sol b/contracts/token/ERC20/extensions/ERC20Capped.sol similarity index 97% rename from contracts/token/ERC20/ERC20Capped.sol rename to contracts/token/ERC20/extensions/ERC20Capped.sol index 5e048dff7a1..05d59cb3d30 100644 --- a/contracts/token/ERC20/ERC20Capped.sol +++ b/contracts/token/ERC20/extensions/ERC20Capped.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./ERC20.sol"; +import "../ERC20.sol"; /** * @dev Extension of {ERC20} that adds a cap to the supply of tokens. diff --git a/contracts/token/ERC20/ERC20Pausable.sol b/contracts/token/ERC20/extensions/ERC20Pausable.sol similarity index 92% rename from contracts/token/ERC20/ERC20Pausable.sol rename to contracts/token/ERC20/extensions/ERC20Pausable.sol index a484fef8112..f08656d023a 100644 --- a/contracts/token/ERC20/ERC20Pausable.sol +++ b/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "./ERC20.sol"; -import "../../utils/Pausable.sol"; +import "../ERC20.sol"; +import "../../../security/Pausable.sol"; /** * @dev ERC20 token with pausable token transfers, minting and burning. diff --git a/contracts/token/ERC20/ERC20Snapshot.sol b/contracts/token/ERC20/extensions/ERC20Snapshot.sol similarity index 98% rename from contracts/token/ERC20/ERC20Snapshot.sol rename to contracts/token/ERC20/extensions/ERC20Snapshot.sol index 56494feb2f7..2246b4e3a2d 100644 --- a/contracts/token/ERC20/ERC20Snapshot.sol +++ b/contracts/token/ERC20/extensions/ERC20Snapshot.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.0; -import "../../utils/Arrays.sol"; -import "../../utils/Counters.sol"; -import "./ERC20.sol"; +import "../ERC20.sol"; +import "../../../utils/Arrays.sol"; +import "../../../utils/Counters.sol"; /** * @dev This contract extends an ERC20 token with a snapshot mechanism. When a snapshot is created, the balances and diff --git a/contracts/drafts/ERC20Permit.sol b/contracts/token/ERC20/extensions/draft-ERC20Permit.sol similarity index 92% rename from contracts/drafts/ERC20Permit.sol rename to contracts/token/ERC20/extensions/draft-ERC20Permit.sol index 7a8b97163ea..1f5cdc2cb71 100644 --- a/contracts/drafts/ERC20Permit.sol +++ b/contracts/token/ERC20/extensions/draft-ERC20Permit.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.0; -import "../token/ERC20/ERC20.sol"; -import "./IERC20Permit.sol"; -import "../cryptography/ECDSA.sol"; -import "../utils/Counters.sol"; -import "./EIP712.sol"; +import "./draft-IERC20Permit.sol"; +import "../ERC20.sol"; +import "../../../utils/cryptography/draft-EIP712.sol"; +import "../../../utils/cryptography/ECDSA.sol"; +import "../../../utils/Counters.sol"; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in diff --git a/contracts/drafts/IERC20Permit.sol b/contracts/token/ERC20/extensions/draft-IERC20Permit.sol similarity index 100% rename from contracts/drafts/IERC20Permit.sol rename to contracts/token/ERC20/extensions/draft-IERC20Permit.sol diff --git a/contracts/presets/ERC20PresetFixedSupply.sol b/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol similarity index 94% rename from contracts/presets/ERC20PresetFixedSupply.sol rename to contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol index b56329d4bbc..4aa0ebf4808 100644 --- a/contracts/presets/ERC20PresetFixedSupply.sol +++ b/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../token/ERC20/ERC20Burnable.sol"; +import "../extensions/ERC20Burnable.sol"; /** * @dev {ERC20} token, including: diff --git a/contracts/presets/ERC20PresetMinterPauser.sol b/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol similarity index 92% rename from contracts/presets/ERC20PresetMinterPauser.sol rename to contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol index a9047d996fd..a9151c630e9 100644 --- a/contracts/presets/ERC20PresetMinterPauser.sol +++ b/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.0; -import "../access/AccessControlEnumerable.sol"; -import "../utils/Context.sol"; -import "../token/ERC20/ERC20.sol"; -import "../token/ERC20/ERC20Burnable.sol"; -import "../token/ERC20/ERC20Pausable.sol"; +import "../ERC20.sol"; +import "../extensions/ERC20Burnable.sol"; +import "../extensions/ERC20Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; /** * @dev {ERC20} token, including: diff --git a/contracts/token/ERC20/SafeERC20.sol b/contracts/token/ERC20/utils/SafeERC20.sol similarity index 98% rename from contracts/token/ERC20/SafeERC20.sol rename to contracts/token/ERC20/utils/SafeERC20.sol index 8534f6c5822..197da6667d1 100644 --- a/contracts/token/ERC20/SafeERC20.sol +++ b/contracts/token/ERC20/utils/SafeERC20.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "./IERC20.sol"; -import "../../utils/Address.sol"; +import "../IERC20.sol"; +import "../../../utils/Address.sol"; /** * @title SafeERC20 diff --git a/contracts/token/ERC20/TokenTimelock.sol b/contracts/token/ERC20/utils/TokenTimelock.sol similarity index 100% rename from contracts/token/ERC20/TokenTimelock.sol rename to contracts/token/ERC20/utils/TokenTimelock.sol diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index c503024aba6..11a71cf7256 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -2,13 +2,14 @@ pragma solidity ^0.8.0; -import "../../utils/Context.sol"; import "./IERC721.sol"; -import "./IERC721Metadata.sol"; import "./IERC721Receiver.sol"; -import "../../introspection/ERC165.sol"; +import "./extensions/IERC721Metadata.sol"; +import "./extensions/IERC721Enumerable.sol"; import "../../utils/Address.sol"; +import "../../utils/Context.sol"; import "../../utils/Strings.sol"; +import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including diff --git a/contracts/token/ERC721/IERC721.sol b/contracts/token/ERC721/IERC721.sol index 4afa6dc52d4..5811e7994ee 100644 --- a/contracts/token/ERC721/IERC721.sol +++ b/contracts/token/ERC721/IERC721.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../../introspection/IERC165.sol"; +import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. diff --git a/contracts/token/ERC721/README.adoc b/contracts/token/ERC721/README.adoc index 08642217d51..07b73d50cbc 100644 --- a/contracts/token/ERC721/README.adoc +++ b/contracts/token/ERC721/README.adoc @@ -39,6 +39,12 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel {{ERC721Burnable}} -== Convenience +== Presets + +These contracts are preconfigured combinations of the above features. They can be used through inheritance or as models to copy and paste their source code. + +{{ERC721PresetMinterPauserAutoId}} + +== Utilities {{ERC721Holder}} diff --git a/contracts/token/ERC721/ERC721Burnable.sol b/contracts/token/ERC721/extensions/ERC721Burnable.sol similarity index 91% rename from contracts/token/ERC721/ERC721Burnable.sol rename to contracts/token/ERC721/extensions/ERC721Burnable.sol index 9a512cc6276..b0512f04817 100644 --- a/contracts/token/ERC721/ERC721Burnable.sol +++ b/contracts/token/ERC721/extensions/ERC721Burnable.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "../../utils/Context.sol"; -import "./ERC721.sol"; +import "../ERC721.sol"; +import "../../../utils/Context.sol"; /** * @title ERC721 Burnable Token diff --git a/contracts/token/ERC721/ERC721Enumerable.sol b/contracts/token/ERC721/extensions/ERC721Enumerable.sol similarity index 99% rename from contracts/token/ERC721/ERC721Enumerable.sol rename to contracts/token/ERC721/extensions/ERC721Enumerable.sol index 4aac28e49b4..8cdcdf8275c 100644 --- a/contracts/token/ERC721/ERC721Enumerable.sol +++ b/contracts/token/ERC721/extensions/ERC721Enumerable.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./ERC721.sol"; +import "../ERC721.sol"; import "./IERC721Enumerable.sol"; /** diff --git a/contracts/token/ERC721/ERC721Pausable.sol b/contracts/token/ERC721/extensions/ERC721Pausable.sol similarity index 92% rename from contracts/token/ERC721/ERC721Pausable.sol rename to contracts/token/ERC721/extensions/ERC721Pausable.sol index 456db1d52aa..9f2fabf7bd4 100644 --- a/contracts/token/ERC721/ERC721Pausable.sol +++ b/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -2,8 +2,8 @@ pragma solidity ^0.8.0; -import "./ERC721.sol"; -import "../../utils/Pausable.sol"; +import "../ERC721.sol"; +import "../../../security/Pausable.sol"; /** * @dev ERC721 token with pausable token transfers, minting and burning. diff --git a/contracts/token/ERC721/IERC721Enumerable.sol b/contracts/token/ERC721/extensions/IERC721Enumerable.sol similarity index 97% rename from contracts/token/ERC721/IERC721Enumerable.sol rename to contracts/token/ERC721/extensions/IERC721Enumerable.sol index 2cb4789658a..6cf0f83698d 100644 --- a/contracts/token/ERC721/IERC721Enumerable.sol +++ b/contracts/token/ERC721/extensions/IERC721Enumerable.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./IERC721.sol"; +import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension diff --git a/contracts/token/ERC721/IERC721Metadata.sol b/contracts/token/ERC721/extensions/IERC721Metadata.sol similarity index 96% rename from contracts/token/ERC721/IERC721Metadata.sol rename to contracts/token/ERC721/extensions/IERC721Metadata.sol index 24f02f838ed..2379baca95a 100644 --- a/contracts/token/ERC721/IERC721Metadata.sol +++ b/contracts/token/ERC721/extensions/IERC721Metadata.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "./IERC721.sol"; +import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension diff --git a/contracts/presets/ERC721PresetMinterPauserAutoId.sol b/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol similarity index 92% rename from contracts/presets/ERC721PresetMinterPauserAutoId.sol rename to contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol index ca1b6b95aee..4d1fbe9e6f7 100644 --- a/contracts/presets/ERC721PresetMinterPauserAutoId.sol +++ b/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.0; -import "../access/AccessControlEnumerable.sol"; -import "../utils/Context.sol"; -import "../utils/Counters.sol"; -import "../token/ERC721/ERC721.sol"; -import "../token/ERC721/ERC721Enumerable.sol"; -import "../token/ERC721/ERC721Burnable.sol"; -import "../token/ERC721/ERC721Pausable.sol"; +import "../ERC721.sol"; +import "../extensions/ERC721Enumerable.sol"; +import "../extensions/ERC721Burnable.sol"; +import "../extensions/ERC721Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; +import "../../../utils/Counters.sol"; /** * @dev {ERC721} token, including: diff --git a/contracts/token/ERC721/ERC721Holder.sol b/contracts/token/ERC721/utils/ERC721Holder.sol similarity index 90% rename from contracts/token/ERC721/ERC721Holder.sol rename to contracts/token/ERC721/utils/ERC721Holder.sol index 6e4858a6b4c..1174ec05375 100644 --- a/contracts/token/ERC721/ERC721Holder.sol +++ b/contracts/token/ERC721/utils/ERC721Holder.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.0; -import "./IERC721Receiver.sol"; +import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * - * Accepts all token transfers. + * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { diff --git a/contracts/token/ERC777/ERC777.sol b/contracts/token/ERC777/ERC777.sol index d33a8a04d44..22021b1386b 100644 --- a/contracts/token/ERC777/ERC777.sol +++ b/contracts/token/ERC777/ERC777.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.0; -import "../../utils/Context.sol"; import "./IERC777.sol"; import "./IERC777Recipient.sol"; import "./IERC777Sender.sol"; -import "../../token/ERC20/IERC20.sol"; +import "../ERC20/IERC20.sol"; import "../../utils/Address.sol"; -import "../../introspection/IERC1820Registry.sol"; +import "../../utils/Context.sol"; +import "../../utils/introspection/IERC1820Registry.sol"; /** * @dev Implementation of the {IERC777} interface. diff --git a/contracts/token/ERC777/README.adoc b/contracts/token/ERC777/README.adoc index 4dee8a661ac..d8f25f06010 100644 --- a/contracts/token/ERC777/README.adoc +++ b/contracts/token/ERC777/README.adoc @@ -22,3 +22,9 @@ Additionally there are interfaces used to develop contracts that react to token {{IERC777Sender}} {{IERC777Recipient}} + +== Presets + +These contracts are preconfigured combinations of features. They can be used through inheritance or as models to copy and paste their source code. + +{{ERC777PresetFixedSupply}} diff --git a/contracts/presets/ERC777PresetFixedSupply.sol b/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol similarity index 94% rename from contracts/presets/ERC777PresetFixedSupply.sol rename to contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol index 0556daccd0e..fb9a6cef223 100644 --- a/contracts/presets/ERC777PresetFixedSupply.sol +++ b/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../token/ERC777/ERC777.sol"; +import "../ERC777.sol"; /** * @dev {ERC777} token, including: diff --git a/contracts/utils/Arrays.sol b/contracts/utils/Arrays.sol index 4bbaa138c87..9a6e7ae0448 100644 --- a/contracts/utils/Arrays.sol +++ b/contracts/utils/Arrays.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../math/Math.sol"; +import "./math/Math.sol"; /** * @dev Collection of functions related to array types. diff --git a/contracts/proxy/Initializable.sol b/contracts/utils/Initializable.sol similarity index 98% rename from contracts/proxy/Initializable.sol rename to contracts/utils/Initializable.sol index 05c3b4f7034..802c1ef902a 100644 --- a/contracts/proxy/Initializable.sol +++ b/contracts/utils/Initializable.sol @@ -3,7 +3,7 @@ // solhint-disable-next-line compiler-version pragma solidity ^0.8.0; -import "../utils/Address.sol"; +import "./Address.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed diff --git a/contracts/payment/PaymentSplitter.sol b/contracts/utils/PaymentSplitter.sol similarity index 98% rename from contracts/payment/PaymentSplitter.sol rename to contracts/utils/PaymentSplitter.sol index f09d101fdbc..b44faae8905 100644 --- a/contracts/payment/PaymentSplitter.sol +++ b/contracts/utils/PaymentSplitter.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.0; -import "../utils/Context.sol"; -import "../math/SafeMath.sol"; -import "../utils/Address.sol"; +import "./Address.sol"; +import "./Context.sol"; +import "./math/SafeMath.sol"; /** * @title PaymentSplitter diff --git a/contracts/utils/README.adoc b/contracts/utils/README.adoc index 3773c411fb1..fc6adc6f342 100644 --- a/contracts/utils/README.adoc +++ b/contracts/utils/README.adoc @@ -5,11 +5,6 @@ NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/ Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives. -Security tools include: - - * {Pausable}: provides a simple way to halt activity in your contracts (often in response to an external threat). - * {ReentrancyGuard}: protects you from https://blog.openzeppelin.com/reentrancy-after-istanbul/[reentrant calls]. - The {Address}, {Arrays} and {Strings} libraries provide more operations related to these native data types, while {SafeCast} adds ways to safely convert between the different signed and unsigned numeric types. For new data types: @@ -27,26 +22,69 @@ As of v3.0, {EnumerableMap} supports `uint256 -> address` (`UintToAddressMap`), Finally, {Create2} contains all necessary utilities to safely use the https://blog.openzeppelin.com/getting-the-most-out-of-create2/[`CREATE2` EVM opcode], without having to deal with low-level assembly. -== Contracts +== Math -{{Pausable}} +{{Math}} -{{ReentrancyGuard}} +{{SafeCast}} -== Libraries +{{SafeMath}} -{{Address}} +{{SignedSafeMath}} -{{Arrays}} +== Cryptography -{{Counters}} +{{ECDSA}} -{{Create2}} +{{MerkleProof}} + +{{EIP712}} + +== Introspection + +This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[type introspection] of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_. + +Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors. + +There are two main ways to approach this. + +* Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`. +* Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts. + +Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security. + +{{IERC165}} + +{{ERC165}} + +{{ERC165Storage}} + +{{ERC165Checker}} + +{{IERC1820Registry}} + +{{IERC1820Implementer}} + +{{ERC1820Implementer}} + +== Data Structures {{EnumerableMap}} {{EnumerableSet}} -{{SafeCast}} +== Libraries + +{{Create2}} + +{{Address}} + +{{Arrays}} + +{{Counters}} {{Strings}} + +== Other + +{{Initializable}} diff --git a/contracts/cryptography/ECDSA.sol b/contracts/utils/cryptography/ECDSA.sol similarity index 98% rename from contracts/cryptography/ECDSA.sol rename to contracts/utils/cryptography/ECDSA.sol index 76dab5d2113..b3ea4077403 100644 --- a/contracts/cryptography/ECDSA.sol +++ b/contracts/utils/cryptography/ECDSA.sol @@ -47,7 +47,7 @@ library ECDSA { } /** - * @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`, + * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { diff --git a/contracts/cryptography/MerkleProof.sol b/contracts/utils/cryptography/MerkleProof.sol similarity index 100% rename from contracts/cryptography/MerkleProof.sol rename to contracts/utils/cryptography/MerkleProof.sol diff --git a/contracts/drafts/EIP712.sol b/contracts/utils/cryptography/draft-EIP712.sol similarity index 99% rename from contracts/drafts/EIP712.sol rename to contracts/utils/cryptography/draft-EIP712.sol index c3be3ea7630..044f50aae1e 100644 --- a/contracts/drafts/EIP712.sol +++ b/contracts/utils/cryptography/draft-EIP712.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; -import "../cryptography/ECDSA.sol"; +import "./ECDSA.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. diff --git a/contracts/payment/escrow/ConditionalEscrow.sol b/contracts/utils/escrow/ConditionalEscrow.sol similarity index 100% rename from contracts/payment/escrow/ConditionalEscrow.sol rename to contracts/utils/escrow/ConditionalEscrow.sol diff --git a/contracts/payment/escrow/Escrow.sol b/contracts/utils/escrow/Escrow.sol similarity index 98% rename from contracts/payment/escrow/Escrow.sol rename to contracts/utils/escrow/Escrow.sol index 9160c172ab6..6f236b1896b 100644 --- a/contracts/payment/escrow/Escrow.sol +++ b/contracts/utils/escrow/Escrow.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.0; import "../../access/Ownable.sol"; -import "../../utils/Address.sol"; +import "../Address.sol"; /** * @title Escrow diff --git a/contracts/payment/escrow/RefundEscrow.sol b/contracts/utils/escrow/RefundEscrow.sol similarity index 100% rename from contracts/payment/escrow/RefundEscrow.sol rename to contracts/utils/escrow/RefundEscrow.sol diff --git a/contracts/introspection/ERC165.sol b/contracts/utils/introspection/ERC165.sol similarity index 100% rename from contracts/introspection/ERC165.sol rename to contracts/utils/introspection/ERC165.sol diff --git a/contracts/introspection/ERC165Checker.sol b/contracts/utils/introspection/ERC165Checker.sol similarity index 100% rename from contracts/introspection/ERC165Checker.sol rename to contracts/utils/introspection/ERC165Checker.sol diff --git a/contracts/introspection/ERC165Storage.sol b/contracts/utils/introspection/ERC165Storage.sol similarity index 100% rename from contracts/introspection/ERC165Storage.sol rename to contracts/utils/introspection/ERC165Storage.sol diff --git a/contracts/introspection/ERC1820Implementer.sol b/contracts/utils/introspection/ERC1820Implementer.sol similarity index 100% rename from contracts/introspection/ERC1820Implementer.sol rename to contracts/utils/introspection/ERC1820Implementer.sol diff --git a/contracts/introspection/IERC165.sol b/contracts/utils/introspection/IERC165.sol similarity index 100% rename from contracts/introspection/IERC165.sol rename to contracts/utils/introspection/IERC165.sol diff --git a/contracts/introspection/IERC1820Implementer.sol b/contracts/utils/introspection/IERC1820Implementer.sol similarity index 100% rename from contracts/introspection/IERC1820Implementer.sol rename to contracts/utils/introspection/IERC1820Implementer.sol diff --git a/contracts/introspection/IERC1820Registry.sol b/contracts/utils/introspection/IERC1820Registry.sol similarity index 100% rename from contracts/introspection/IERC1820Registry.sol rename to contracts/utils/introspection/IERC1820Registry.sol diff --git a/contracts/math/Math.sol b/contracts/utils/math/Math.sol similarity index 100% rename from contracts/math/Math.sol rename to contracts/utils/math/Math.sol diff --git a/contracts/utils/SafeCast.sol b/contracts/utils/math/SafeCast.sol similarity index 99% rename from contracts/utils/SafeCast.sol rename to contracts/utils/math/SafeCast.sol index 860ef0b7a2d..5415462c19a 100644 --- a/contracts/utils/SafeCast.sol +++ b/contracts/utils/math/SafeCast.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; - /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. @@ -19,7 +18,6 @@ pragma solidity ^0.8.0; * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { - /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). diff --git a/contracts/math/SafeMath.sol b/contracts/utils/math/SafeMath.sol similarity index 98% rename from contracts/math/SafeMath.sol rename to contracts/utils/math/SafeMath.sol index b1720f31e0d..af8f9e8549a 100644 --- a/contracts/math/SafeMath.sol +++ b/contracts/utils/math/SafeMath.sol @@ -8,6 +8,9 @@ pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations. + * + * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler + * now has built in overflow checking. */ library SafeMath { /** diff --git a/contracts/math/SignedSafeMath.sol b/contracts/utils/math/SignedSafeMath.sol similarity index 88% rename from contracts/math/SignedSafeMath.sol rename to contracts/utils/math/SignedSafeMath.sol index 15530c27b4e..d54b8ff307a 100644 --- a/contracts/math/SignedSafeMath.sol +++ b/contracts/utils/math/SignedSafeMath.sol @@ -3,8 +3,10 @@ pragma solidity ^0.8.0; /** - * @title SignedSafeMath - * @dev Signed math operations that revert on error. + * @dev Wrappers over Solidity's arithmetic operations. + * + * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler + * now has built in overflow checking. */ library SignedSafeMath { /** diff --git a/contracts/utils/EnumerableMap.sol b/contracts/utils/structs/EnumerableMap.sol similarity index 100% rename from contracts/utils/EnumerableMap.sol rename to contracts/utils/structs/EnumerableMap.sol diff --git a/contracts/utils/EnumerableSet.sol b/contracts/utils/structs/EnumerableSet.sol similarity index 100% rename from contracts/utils/EnumerableSet.sol rename to contracts/utils/structs/EnumerableSet.sol diff --git a/package-lock.json b/package-lock.json index f62eee635e7..a97e6fd92f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19544,6 +19544,12 @@ "ext": "^1.1.2" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -26353,6 +26359,155 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, + "replace-in-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-6.2.0.tgz", + "integrity": "sha512-Im2AF9G/qgkYneOc9QwWwUS/efyyonTUBvzXS2VXuxPawE5yQIjT/e6x4CTijO0Quq48lfAujuo+S89RR2TP2Q==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "glob": "^7.1.6", + "yargs": "^16.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", + "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.5", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.5.tgz", + "integrity": "sha512-jYRGS3zWy20NtDtK2kBgo/TlAoy5YUuhD9/LZ7z7W4j1Fdw2cqD0xEEclf8fxc8xjD6X5Qr+qQQwCEsP8iRiYg==", + "dev": true + } + } + }, "req-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", diff --git a/package.json b/package.json index fa558cabdb3..575448ee164 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,9 @@ "!/contracts/mocks", "/test/behaviors" ], + "bin": { + "openzeppelin-contracts-migrate-imports": "scripts/migrate-imports.js" + }, "scripts": { "compile": "hardhat compile", "coverage": "hardhat coverage", diff --git a/scripts/migrate-imports.js b/scripts/migrate-imports.js new file mode 100755 index 00000000000..63acce83c6e --- /dev/null +++ b/scripts/migrate-imports.js @@ -0,0 +1,174 @@ +#!/usr/bin/env node + +const { promises: fs } = require('fs'); +const path = require('path'); + +const pathUpdates = { + // 'access/AccessControl.sol': undefined, + // 'access/Ownable.sol': undefined, + 'access/TimelockController.sol': 'governance/TimelockController.sol', + 'cryptography/ECDSA.sol': 'utils/cryptography/ECDSA.sol', + 'cryptography/MerkleProof.sol': 'utils/cryptography/MerkleProof.sol', + 'drafts/EIP712.sol': 'utils/cryptography/draft-EIP712.sol', + 'drafts/ERC20Permit.sol': 'token/ERC20/extensions/draft-ERC20Permit.sol', + 'drafts/IERC20Permit.sol': 'token/ERC20/extensions/draft-IERC20Permit.sol', + 'GSN/Context.sol': 'utils/Context.sol', + // 'GSN/GSNRecipientERC20Fee.sol': undefined, + // 'GSN/GSNRecipientSignature.sol': undefined, + // 'GSN/GSNRecipient.sol': undefined, + // 'GSN/IRelayHub.sol': undefined, + // 'GSN/IRelayRecipient.sol': undefined, + 'introspection/ERC165Checker.sol': 'utils/introspection/ERC165Checker.sol', + 'introspection/ERC165.sol': 'utils/introspection/ERC165.sol', + 'introspection/ERC1820Implementer.sol': 'utils/introspection/ERC1820Implementer.sol', + 'introspection/IERC165.sol': 'utils/introspection/IERC165.sol', + 'introspection/IERC1820Implementer.sol': 'utils/introspection/IERC1820Implementer.sol', + 'introspection/IERC1820Registry.sol': 'utils/introspection/IERC1820Registry.sol', + 'math/Math.sol': 'utils/math/Math.sol', + 'math/SafeMath.sol': 'utils/math/SafeMath.sol', + 'math/SignedSafeMath.sol': 'utils/math/SignedSafeMath.sol', + 'payment/escrow/ConditionalEscrow.sol': 'utils/escrow/ConditionalEscrow.sol', + 'payment/escrow/Escrow.sol': 'utils/escrow/Escrow.sol', + 'payment/escrow/RefundEscrow.sol': 'utils/escrow/RefundEscrow.sol', + 'payment/PaymentSplitter.sol': 'utils/PaymentSplitter.sol', + 'payment/PullPayment.sol': 'security/PullPayment.sol', + 'presets/ERC1155PresetMinterPauser.sol': 'token/ERC1155/presets/ERC1155PresetMinterPauser.sol', + 'presets/ERC20PresetFixedSupply.sol': 'token/ERC20/presets/ERC20PresetFixedSupply.sol', + 'presets/ERC20PresetMinterPauser.sol': 'token/ERC20/presets/ERC20PresetMinterPauser.sol', + 'presets/ERC721PresetMinterPauserAutoId.sol': 'token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol', + 'presets/ERC777PresetFixedSupply.sol': 'token/ERC777/presets/ERC777PresetFixedSupply.sol', + 'proxy/BeaconProxy.sol': 'proxy/beacon/BeaconProxy.sol', + // 'proxy/Clones.sol': undefined, + 'proxy/IBeacon.sol': 'proxy/beacon/IBeacon.sol', + 'proxy/Initializable.sol': 'utils/Initializable.sol', + 'proxy/ProxyAdmin.sol': 'proxy/transparent/ProxyAdmin.sol', + // 'proxy/Proxy.sol': undefined, + 'proxy/TransparentUpgradeableProxy.sol': 'proxy/transparent/TransparentUpgradeableProxy.sol', + 'proxy/UpgradeableBeacon.sol': 'proxy/beacon/UpgradeableBeacon.sol', + // 'proxy/UpgradeableProxy.sol': undefined, + 'token/ERC1155/ERC1155Burnable.sol': 'token/ERC1155/extensions/ERC1155Burnable.sol', + 'token/ERC1155/ERC1155Holder.sol': 'token/ERC1155/utils/ERC1155Holder.sol', + 'token/ERC1155/ERC1155Pausable.sol': 'token/ERC1155/extensions/ERC1155Pausable.sol', + 'token/ERC1155/ERC1155Receiver.sol': 'token/ERC1155/utils/ERC1155Receiver.sol', + // 'token/ERC1155/ERC1155.sol': undefined, + 'token/ERC1155/IERC1155MetadataURI.sol': 'token/ERC1155/extensions/IERC1155MetadataURI.sol', + // 'token/ERC1155/IERC1155Receiver.sol': undefined, + // 'token/ERC1155/IERC1155.sol': undefined, + 'token/ERC20/ERC20Burnable.sol': 'token/ERC20/extensions/ERC20Burnable.sol', + 'token/ERC20/ERC20Capped.sol': 'token/ERC20/extensions/ERC20Capped.sol', + 'token/ERC20/ERC20Pausable.sol': 'token/ERC20/extensions/ERC20Pausable.sol', + 'token/ERC20/ERC20Snapshot.sol': 'token/ERC20/extensions/ERC20Snapshot.sol', + // 'token/ERC20/ERC20.sol': undefined, + // 'token/ERC20/IERC20.sol': undefined, + 'token/ERC20/SafeERC20.sol': 'token/ERC20/utils/SafeERC20.sol', + 'token/ERC20/TokenTimelock.sol': 'token/ERC20/utils/TokenTimelock.sol', + 'token/ERC721/ERC721Burnable.sol': 'token/ERC721/extensions/ERC721Burnable.sol', + 'token/ERC721/ERC721Holder.sol': 'token/ERC721/utils/ERC721Holder.sol', + 'token/ERC721/ERC721Pausable.sol': 'token/ERC721/extensions/ERC721Pausable.sol', + // 'token/ERC721/ERC721.sol': undefined, + 'token/ERC721/IERC721Enumerable.sol': 'token/ERC721/extensions/IERC721Enumerable.sol', + 'token/ERC721/IERC721Metadata.sol': 'token/ERC721/extensions/IERC721Metadata.sol', + // 'token/ERC721/IERC721Receiver.sol': undefined, + // 'token/ERC721/IERC721.sol': undefined, + // 'token/ERC777/ERC777.sol': undefined, + // 'token/ERC777/IERC777Recipient.sol': undefined, + // 'token/ERC777/IERC777Sender.sol': undefined, + // 'token/ERC777/IERC777.sol': undefined, + // 'utils/Address.sol': undefined, + // 'utils/Arrays.sol': undefined, + // 'utils/Context.sol': undefined, + // 'utils/Counters.sol': undefined, + // 'utils/Create2.sol': undefined, + 'utils/EnumerableMap.sol': 'utils/structs/EnumerableMap.sol', + 'utils/EnumerableSet.sol': 'utils/structs/EnumerableSet.sol', + 'utils/Pausable.sol': 'security/Pausable.sol', + 'utils/ReentrancyGuard.sol': 'security/ReentrancyGuard.sol', + 'utils/SafeCast.sol': 'utils/math/SafeCast.sol', + // 'utils/Strings.sol': undefined, +}; + +async function main (paths = [ 'contracts' ]) { + const files = await listFilesRecursively(paths, /\.sol$/); + + const updatedFiles = []; + for (const file of files) { + if (await updateFile(file, updateImportPaths)) { + updatedFiles.push(file); + } + } + + if (updatedFiles.length > 0) { + console.log(`${updatedFiles.length} file(s) were updated`); + for (const c of updatedFiles) { + console.log('-', c); + } + } else { + console.log('No files were updated'); + } +} + +async function listFilesRecursively (paths, filter) { + const queue = paths; + const files = []; + + while (queue.length > 0) { + const top = queue.shift(); + const stat = await fs.stat(top); + if (stat.isFile()) { + if (top.match(filter)) { + files.push(top); + } + } else if (stat.isDirectory()) { + for (const name of await fs.readdir(top)) { + queue.push(path.join(top, name)); + } + } + } + + return files; +} + +async function updateFile (file, update) { + const content = await fs.readFile(file, 'utf8'); + const updatedContent = update(content); + if (updatedContent !== content) { + await fs.writeFile(file, updatedContent); + return true; + } else { + return false; + } +} + +function updateImportPaths (source) { + for (const [ oldPath, newPath ] of Object.entries(pathUpdates)) { + source = source.replace( + path.join('@openzeppelin/contracts', oldPath), + path.join('@openzeppelin/contracts', newPath), + ); + source = source.replace( + path.join('@openzeppelin/contracts-upgradeable', getUpgradeablePath(oldPath)), + path.join('@openzeppelin/contracts-upgradeable', getUpgradeablePath(newPath)), + ); + } + + return source; +} + +function getUpgradeablePath (file) { + const { dir, name, ext } = path.parse(file); + const upgradeableName = name + 'Upgradeable'; + return path.format({ dir, ext, name: upgradeableName }); +} + +module.exports = { + pathUpdates, + updateImportPaths, +}; + +if (require.main === module) { + const args = process.argv.length > 2 ? process.argv.slice(2) : undefined; + main(args).catch(e => { + console.error(e); + process.exit(1); + }); +} diff --git a/scripts/prepack.sh b/scripts/prepack.sh index bc4f7a24977..6f1bd4c32f1 100755 --- a/scripts/prepack.sh +++ b/scripts/prepack.sh @@ -1,10 +1,12 @@ #!/usr/bin/env bash set -euo pipefail +shopt -s globstar # cross platform `mkdir -p` node -e 'fs.mkdirSync("build/contracts", { recursive: true })' -cp artifacts/*.json build/contracts +cp artifacts/contracts/**/*.json build/contracts +rm build/contracts/*.dbg.json node scripts/remove-ignored-artifacts.js diff --git a/scripts/remove-ignored-artifacts.js b/scripts/remove-ignored-artifacts.js index 8c013deccc4..95cf89c9298 100644 --- a/scripts/remove-ignored-artifacts.js +++ b/scripts/remove-ignored-artifacts.js @@ -23,7 +23,12 @@ const ignorePatternsSubtrees = ignorePatterns .concat(ignorePatterns.map(pat => path.join(pat, '**/*'))) .map(p => p.replace(/^\//, '')); -const solcOutput = readJSON('cache/solc-output.json'); +const buildinfo = 'artifacts/build-info'; +const filenames = fs.readdirSync(buildinfo); +if (filenames.length !== 1) { + throw new Error(`There should only be one file in ${buildinfo}`); +} +const solcOutput = readJSON(path.join(buildinfo, filenames[0])).output; const artifactsDir = 'build/contracts'; diff --git a/test/access/TimelockController.test.js b/test/governance/TimelockController.test.js similarity index 100% rename from test/access/TimelockController.test.js rename to test/governance/TimelockController.test.js diff --git a/test/migrate-imports.test.js b/test/migrate-imports.test.js new file mode 100644 index 00000000000..a85fce21e13 --- /dev/null +++ b/test/migrate-imports.test.js @@ -0,0 +1,25 @@ +const path = require('path'); +const { promises: fs, constants: { F_OK } } = require('fs'); +const { expect } = require('chai'); + +const { pathUpdates, updateImportPaths } = require('../scripts/migrate-imports.js'); + +describe('migrate-imports.js', function () { + it('every new path exists', async function () { + for (const p of Object.values(pathUpdates)) { + await fs.access(path.join('contracts', p), F_OK); + } + }); + + it('replaces import paths in a file', async function () { + const source = ` +import '@openzeppelin/contracts/math/Math.sol'; +import '@openzeppelin/contracts-upgradeable/math/MathUpgradeable.sol'; + `; + const expected = ` +import '@openzeppelin/contracts/utils/math/Math.sol'; +import '@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol'; + `; + expect(updateImportPaths(source)).to.equal(expected); + }); +}); diff --git a/test/proxy/BeaconProxy.test.js b/test/proxy/beacon/BeaconProxy.test.js similarity index 100% rename from test/proxy/BeaconProxy.test.js rename to test/proxy/beacon/BeaconProxy.test.js diff --git a/test/proxy/UpgradeableBeacon.test.js b/test/proxy/beacon/UpgradeableBeacon.test.js similarity index 100% rename from test/proxy/UpgradeableBeacon.test.js rename to test/proxy/beacon/UpgradeableBeacon.test.js diff --git a/test/proxy/TransparentUpgradeableProxy.behaviour.js b/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js similarity index 100% rename from test/proxy/TransparentUpgradeableProxy.behaviour.js rename to test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js diff --git a/test/proxy/TransparentUpgradeableProxy.test.js b/test/proxy/transparent/TransparentUpgradeableProxy.test.js similarity index 88% rename from test/proxy/TransparentUpgradeableProxy.test.js rename to test/proxy/transparent/TransparentUpgradeableProxy.test.js index 984fb2c063a..cf8206996bc 100644 --- a/test/proxy/TransparentUpgradeableProxy.test.js +++ b/test/proxy/transparent/TransparentUpgradeableProxy.test.js @@ -1,4 +1,4 @@ -const shouldBehaveLikeUpgradeableProxy = require('./UpgradeableProxy.behaviour'); +const shouldBehaveLikeUpgradeableProxy = require('../UpgradeableProxy.behaviour'); const shouldBehaveLikeTransparentUpgradeableProxy = require('./TransparentUpgradeableProxy.behaviour'); const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy'); diff --git a/test/utils/Pausable.test.js b/test/security/Pausable.test.js similarity index 100% rename from test/utils/Pausable.test.js rename to test/security/Pausable.test.js diff --git a/test/payment/PullPayment.test.js b/test/security/PullPayment.test.js similarity index 100% rename from test/payment/PullPayment.test.js rename to test/security/PullPayment.test.js diff --git a/test/utils/ReentrancyGuard.test.js b/test/security/ReentrancyGuard.test.js similarity index 100% rename from test/utils/ReentrancyGuard.test.js rename to test/security/ReentrancyGuard.test.js diff --git a/test/token/ERC1155/ERC1155.behavior.js b/test/token/ERC1155/ERC1155.behavior.js index 62fc9f7b94e..13b08ac638c 100644 --- a/test/token/ERC1155/ERC1155.behavior.js +++ b/test/token/ERC1155/ERC1155.behavior.js @@ -3,7 +3,7 @@ const { ZERO_ADDRESS } = constants; const { expect } = require('chai'); -const { shouldSupportInterfaces } = require('../../introspection/SupportsInterface.behavior'); +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); const ERC1155ReceiverMock = artifacts.require('ERC1155ReceiverMock'); diff --git a/test/token/ERC1155/ERC1155Burnable.test.js b/test/token/ERC1155/extensions/ERC1155Burnable.test.js similarity index 100% rename from test/token/ERC1155/ERC1155Burnable.test.js rename to test/token/ERC1155/extensions/ERC1155Burnable.test.js diff --git a/test/token/ERC1155/ERC1155Pausable.test.js b/test/token/ERC1155/extensions/ERC1155Pausable.test.js similarity index 100% rename from test/token/ERC1155/ERC1155Pausable.test.js rename to test/token/ERC1155/extensions/ERC1155Pausable.test.js diff --git a/test/presets/ERC1155PresetMinterPauser.test.js b/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js similarity index 100% rename from test/presets/ERC1155PresetMinterPauser.test.js rename to test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js diff --git a/test/token/ERC1155/ERC1155Holder.test.js b/test/token/ERC1155/utils/ERC1155Holder.test.js similarity index 95% rename from test/token/ERC1155/ERC1155Holder.test.js rename to test/token/ERC1155/utils/ERC1155Holder.test.js index 957061e4bd2..41225c23823 100644 --- a/test/token/ERC1155/ERC1155Holder.test.js +++ b/test/token/ERC1155/utils/ERC1155Holder.test.js @@ -5,7 +5,7 @@ const ERC1155Mock = artifacts.require('ERC1155Mock'); const { expect } = require('chai'); -const { shouldSupportInterfaces } = require('../../introspection/SupportsInterface.behavior'); +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); contract('ERC1155Holder', function (accounts) { const [creator] = accounts; diff --git a/test/token/ERC20/behaviors/ERC20Burnable.behavior.js b/test/token/ERC20/extensions/ERC20Burnable.behavior.js similarity index 100% rename from test/token/ERC20/behaviors/ERC20Burnable.behavior.js rename to test/token/ERC20/extensions/ERC20Burnable.behavior.js diff --git a/test/token/ERC20/ERC20Burnable.test.js b/test/token/ERC20/extensions/ERC20Burnable.test.js similarity index 85% rename from test/token/ERC20/ERC20Burnable.test.js rename to test/token/ERC20/extensions/ERC20Burnable.test.js index 11631a7e023..8aa4fb66c5c 100644 --- a/test/token/ERC20/ERC20Burnable.test.js +++ b/test/token/ERC20/extensions/ERC20Burnable.test.js @@ -1,6 +1,6 @@ const { BN } = require('@openzeppelin/test-helpers'); -const { shouldBehaveLikeERC20Burnable } = require('./behaviors/ERC20Burnable.behavior'); +const { shouldBehaveLikeERC20Burnable } = require('./ERC20Burnable.behavior'); const ERC20BurnableMock = artifacts.require('ERC20BurnableMock'); contract('ERC20Burnable', function (accounts) { diff --git a/test/token/ERC20/behaviors/ERC20Capped.behavior.js b/test/token/ERC20/extensions/ERC20Capped.behavior.js similarity index 100% rename from test/token/ERC20/behaviors/ERC20Capped.behavior.js rename to test/token/ERC20/extensions/ERC20Capped.behavior.js diff --git a/test/token/ERC20/ERC20Capped.test.js b/test/token/ERC20/extensions/ERC20Capped.test.js similarity index 89% rename from test/token/ERC20/ERC20Capped.test.js rename to test/token/ERC20/extensions/ERC20Capped.test.js index 3b7e75e3e59..76532cefd8f 100644 --- a/test/token/ERC20/ERC20Capped.test.js +++ b/test/token/ERC20/extensions/ERC20Capped.test.js @@ -1,5 +1,5 @@ const { BN, ether, expectRevert } = require('@openzeppelin/test-helpers'); -const { shouldBehaveLikeERC20Capped } = require('./behaviors/ERC20Capped.behavior'); +const { shouldBehaveLikeERC20Capped } = require('./ERC20Capped.behavior'); const ERC20Capped = artifacts.require('ERC20CappedMock'); diff --git a/test/token/ERC20/ERC20Pausable.test.js b/test/token/ERC20/extensions/ERC20Pausable.test.js similarity index 100% rename from test/token/ERC20/ERC20Pausable.test.js rename to test/token/ERC20/extensions/ERC20Pausable.test.js diff --git a/test/token/ERC20/ERC20Snapshot.test.js b/test/token/ERC20/extensions/ERC20Snapshot.test.js similarity index 100% rename from test/token/ERC20/ERC20Snapshot.test.js rename to test/token/ERC20/extensions/ERC20Snapshot.test.js diff --git a/test/drafts/ERC20Permit.test.js b/test/token/ERC20/extensions/draft-ERC20Permit.test.js similarity index 98% rename from test/drafts/ERC20Permit.test.js rename to test/token/ERC20/extensions/draft-ERC20Permit.test.js index 2ba38e37c3c..9aa64456110 100644 --- a/test/drafts/ERC20Permit.test.js +++ b/test/token/ERC20/extensions/draft-ERC20Permit.test.js @@ -10,7 +10,7 @@ const Wallet = require('ethereumjs-wallet').default; const ERC20PermitMock = artifacts.require('ERC20PermitMock'); -const { EIP712Domain, domainSeparator } = require('../helpers/eip712'); +const { EIP712Domain, domainSeparator } = require('../../../helpers/eip712'); const Permit = [ { name: 'owner', type: 'address' }, diff --git a/test/presets/ERC20PresetFixedSupply.test.js b/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js similarity index 100% rename from test/presets/ERC20PresetFixedSupply.test.js rename to test/token/ERC20/presets/ERC20PresetFixedSupply.test.js diff --git a/test/presets/ERC20PresetMinterPauser.test.js b/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js similarity index 100% rename from test/presets/ERC20PresetMinterPauser.test.js rename to test/token/ERC20/presets/ERC20PresetMinterPauser.test.js diff --git a/test/token/ERC20/SafeERC20.test.js b/test/token/ERC20/utils/SafeERC20.test.js similarity index 100% rename from test/token/ERC20/SafeERC20.test.js rename to test/token/ERC20/utils/SafeERC20.test.js diff --git a/test/token/ERC20/TokenTimelock.test.js b/test/token/ERC20/utils/TokenTimelock.test.js similarity index 100% rename from test/token/ERC20/TokenTimelock.test.js rename to test/token/ERC20/utils/TokenTimelock.test.js diff --git a/test/token/ERC721/ERC721.behavior.js b/test/token/ERC721/ERC721.behavior.js index f15f059d8a3..877e542bc6d 100644 --- a/test/token/ERC721/ERC721.behavior.js +++ b/test/token/ERC721/ERC721.behavior.js @@ -2,7 +2,7 @@ const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test const { expect } = require('chai'); const { ZERO_ADDRESS } = constants; -const { shouldSupportInterfaces } = require('../../introspection/SupportsInterface.behavior'); +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); const ERC721ReceiverMock = artifacts.require('ERC721ReceiverMock'); diff --git a/test/token/ERC721/ERC721Burnable.test.js b/test/token/ERC721/extensions/ERC721Burnable.test.js similarity index 100% rename from test/token/ERC721/ERC721Burnable.test.js rename to test/token/ERC721/extensions/ERC721Burnable.test.js diff --git a/test/token/ERC721/ERC721Pausable.test.js b/test/token/ERC721/extensions/ERC721Pausable.test.js similarity index 100% rename from test/token/ERC721/ERC721Pausable.test.js rename to test/token/ERC721/extensions/ERC721Pausable.test.js diff --git a/test/presets/ERC721PresetMinterPauserAutoId.test.js b/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js similarity index 100% rename from test/presets/ERC721PresetMinterPauserAutoId.test.js rename to test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js diff --git a/test/token/ERC721/ERC721Holder.test.js b/test/token/ERC721/utils/ERC721Holder.test.js similarity index 100% rename from test/token/ERC721/ERC721Holder.test.js rename to test/token/ERC721/utils/ERC721Holder.test.js diff --git a/test/presets/ERC777PresetFixedSupply.test.js b/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js similarity index 100% rename from test/presets/ERC777PresetFixedSupply.test.js rename to test/token/ERC777/presets/ERC777PresetFixedSupply.test.js diff --git a/test/proxy/Initializable.test.js b/test/utils/Initializable.test.js similarity index 100% rename from test/proxy/Initializable.test.js rename to test/utils/Initializable.test.js diff --git a/test/payment/PaymentSplitter.test.js b/test/utils/PaymentSplitter.test.js similarity index 100% rename from test/payment/PaymentSplitter.test.js rename to test/utils/PaymentSplitter.test.js diff --git a/test/cryptography/ECDSA.test.js b/test/utils/cryptography/ECDSA.test.js similarity index 98% rename from test/cryptography/ECDSA.test.js rename to test/utils/cryptography/ECDSA.test.js index 4a360a8a301..9062b6913f9 100644 --- a/test/cryptography/ECDSA.test.js +++ b/test/utils/cryptography/ECDSA.test.js @@ -1,5 +1,5 @@ const { expectRevert } = require('@openzeppelin/test-helpers'); -const { toEthSignedMessageHash, fixSignature } = require('../helpers/sign'); +const { toEthSignedMessageHash, fixSignature } = require('../../helpers/sign'); const { expect } = require('chai'); diff --git a/test/cryptography/MerkleProof.test.js b/test/utils/cryptography/MerkleProof.test.js similarity index 96% rename from test/cryptography/MerkleProof.test.js rename to test/utils/cryptography/MerkleProof.test.js index 9c6e65b899b..0ef5b3b08e9 100644 --- a/test/cryptography/MerkleProof.test.js +++ b/test/utils/cryptography/MerkleProof.test.js @@ -1,6 +1,6 @@ require('@openzeppelin/test-helpers'); -const { MerkleTree } = require('../helpers/merkleTree.js'); +const { MerkleTree } = require('../../helpers/merkleTree.js'); const { keccakFromString, bufferToHex } = require('ethereumjs-util'); const { expect } = require('chai'); diff --git a/test/drafts/EIP712.test.js b/test/utils/cryptography/draft-EIP712.test.js similarity index 95% rename from test/drafts/EIP712.test.js rename to test/utils/cryptography/draft-EIP712.test.js index ef7a55e766a..9e26a87c6d2 100644 --- a/test/drafts/EIP712.test.js +++ b/test/utils/cryptography/draft-EIP712.test.js @@ -1,7 +1,7 @@ const ethSigUtil = require('eth-sig-util'); const Wallet = require('ethereumjs-wallet').default; -const { EIP712Domain, domainSeparator } = require('../helpers/eip712'); +const { EIP712Domain, domainSeparator } = require('../../helpers/eip712'); const EIP712 = artifacts.require('EIP712External'); diff --git a/test/payment/escrow/ConditionalEscrow.test.js b/test/utils/escrow/ConditionalEscrow.test.js similarity index 100% rename from test/payment/escrow/ConditionalEscrow.test.js rename to test/utils/escrow/ConditionalEscrow.test.js diff --git a/test/payment/escrow/Escrow.behavior.js b/test/utils/escrow/Escrow.behavior.js similarity index 100% rename from test/payment/escrow/Escrow.behavior.js rename to test/utils/escrow/Escrow.behavior.js diff --git a/test/payment/escrow/Escrow.test.js b/test/utils/escrow/Escrow.test.js similarity index 100% rename from test/payment/escrow/Escrow.test.js rename to test/utils/escrow/Escrow.test.js diff --git a/test/payment/escrow/RefundEscrow.test.js b/test/utils/escrow/RefundEscrow.test.js similarity index 100% rename from test/payment/escrow/RefundEscrow.test.js rename to test/utils/escrow/RefundEscrow.test.js diff --git a/test/introspection/ERC165.test.js b/test/utils/introspection/ERC165.test.js similarity index 100% rename from test/introspection/ERC165.test.js rename to test/utils/introspection/ERC165.test.js diff --git a/test/introspection/ERC165Checker.test.js b/test/utils/introspection/ERC165Checker.test.js similarity index 100% rename from test/introspection/ERC165Checker.test.js rename to test/utils/introspection/ERC165Checker.test.js diff --git a/test/introspection/ERC165Storage.test.js b/test/utils/introspection/ERC165Storage.test.js similarity index 100% rename from test/introspection/ERC165Storage.test.js rename to test/utils/introspection/ERC165Storage.test.js diff --git a/test/introspection/ERC1820Implementer.test.js b/test/utils/introspection/ERC1820Implementer.test.js similarity index 100% rename from test/introspection/ERC1820Implementer.test.js rename to test/utils/introspection/ERC1820Implementer.test.js diff --git a/test/introspection/SupportsInterface.behavior.js b/test/utils/introspection/SupportsInterface.behavior.js similarity index 100% rename from test/introspection/SupportsInterface.behavior.js rename to test/utils/introspection/SupportsInterface.behavior.js diff --git a/test/math/Math.test.js b/test/utils/math/Math.test.js similarity index 100% rename from test/math/Math.test.js rename to test/utils/math/Math.test.js diff --git a/test/utils/SafeCast.test.js b/test/utils/math/SafeCast.test.js similarity index 100% rename from test/utils/SafeCast.test.js rename to test/utils/math/SafeCast.test.js diff --git a/test/math/SafeMath.test.js b/test/utils/math/SafeMath.test.js similarity index 100% rename from test/math/SafeMath.test.js rename to test/utils/math/SafeMath.test.js diff --git a/test/math/SignedSafeMath.test.js b/test/utils/math/SignedSafeMath.test.js similarity index 100% rename from test/math/SignedSafeMath.test.js rename to test/utils/math/SignedSafeMath.test.js diff --git a/test/utils/EnumerableMap.test.js b/test/utils/structs/EnumerableMap.test.js similarity index 100% rename from test/utils/EnumerableMap.test.js rename to test/utils/structs/EnumerableMap.test.js diff --git a/test/utils/EnumerableSet.behavior.js b/test/utils/structs/EnumerableSet.behavior.js similarity index 100% rename from test/utils/EnumerableSet.behavior.js rename to test/utils/structs/EnumerableSet.behavior.js diff --git a/test/utils/EnumerableSet.test.js b/test/utils/structs/EnumerableSet.test.js similarity index 100% rename from test/utils/EnumerableSet.test.js rename to test/utils/structs/EnumerableSet.test.js