OpenZeppelin Contracts 4.0 Beta

Due to the new built-in overflow checks in Solidity 0.8, which mark the end of the SafeMath era, this upcoming release of OpenZeppelin Contracts is a new major version of the library.

We used this opportunity to include a few small breaking changes that we had in the backlog. We’re putting out a beta release to ask for feedback on these changes, and to ask if there are any other breaking changes that people think should be included.

If you want to support the project check out the notes below, try out the code, and let us know your thoughts!


These are the breaking changes that will be included in Contracts 4.0.

Reorganized Repository

The most visible change you will find is that some of the contracts were moved to different directories in the repository and npm package.

The reasoning behind this change was that the previous organization was not very good for discoverability of all of the features we offer, and in many cases could be confusing for new users learning about the project and how to use it.

Not all files were moved, but those that were will require users to change their import paths after upgrading to 4.0. In order to mitigate the impact of this breaking change, we’re also including a script that can be run with npx openzeppelin-contracts-migrate-imports after upgrading, that will automatically adjust import paths in Solidity files.

Check out the contracts directory on GitHub and navigate around.

Storage Optimizations

Given the current high gas prices and upcoming opcode repricing in the Berlin hard fork, we turned our attention to a few places where storage usage could be optimized or entirely removed. These changes result in cheaper deployment and lower runtime costs.

If there are any other optimizations we’ve missed, make sure to let us know so we can include them in the release.

ERC20 Decimals

The decimals number used to be kept in storage and was configurable through an internal _setDecimals function. Both the storage variable and internal function are now removed, and customization of a token’s decimals is now done by overriding the decimals function.

This is a pattern we intend to use more in order to avoid the usage of storage variables for customizing contract behavior.

Check out ERC20 on GitHub.

ERC165

Similarly, supported ERC165 interfaces were kept in storage in order to offer an internal _registerInterface function that made things simple to set up. We’ve now changed this so that storage is no longer used, and instead the functionality is implemented through Solidity overrides. Users are encouraged to do the same for any additional supported interfaces, but the old storage-based implementation is still available as ERC165Storage.

Check out ERC165 and ERC165Storage on GitHub.

ERC721 Enumerability and URIs

Our implementation of the ERC721 token (an NFT) was made enumerable by default in version 3.0.0, with no way to opt out of it. This was controversial because it adds to deployment and runtime costs. We’ve now removed enumerability from the base contract and made it an optional extension.

The metadata extension is still included in our base ERC721 contract, just as ERC20 metadata in our base ERC20 token. These extensions are technically optional but universally included in all tokens. We include them by default so that users don’t have to deal with more inheritance to get the basic requirements set up.

One part of the ERC721 metadata extension that was not well optimized was the fact that token URIs (of which there is one per token id of an NFT) were kept in storage individually. We’ve changed this so that the default behavior does not rely on storage. There is now an internal _baseURI() function that can be overriden to return a string. If this string is available, it will be concatenated with the token ID to generate the token URI. This default behavior can be entirely overriden if a different one is required.

Check out ERC721 and ERC721Enumerable on GitHub.

AccessControl Enumerability

We think AccessControl is a great choice for projects that need to grow beyond the Ownable pattern. It allows defining separate roles for the different tasks in a contract that require authorization, and it provides a lot of flexibility as to how those roles are managed, supporting a hierarchy of roles if necessary.

This contract used to come with enumerability built in (of addresses assigned to each role), with a cost that may have discouraged its use. We decided to make it simpler by removing the default of on-chain enumerability.

The information can still be obtained off-chain by consuming the log of events of a contract. If on-chain enumerability is required, there is a separate AccessControlEnumerable contract that implements it.

Check out AccessControl and AccessControlEnumerable.

Meta Transactions (GSN v2)

The OpenGSN team has been busy working on GSNv2, and GSNv1 was put in maintenance mode. Thus, we’ve removed our contracts for GSNv1 integration and begun adding support for GSNv2.

The new version is a more modular system and requires a lot less code. The core is in ERC2771Context, while MinimalForwarder is a utility contract that can assist during testing of a GSNv2-based system.


SafeMath

As I mentioned at the beginning, Solidity 0.8 marks the end of the SafeMath era, as overflow checks are now built into the compiler.

You will find that SafeMath is still in the repository, athough it is now just a wrapper over the built-in overflow checks. The library was kept to ease the transition, but we encourage users on Solidity 0.8 to remove SafeMath from their contracts and rely on the compiler checks exclusively. We may fully remove it from the repository in a future major release.

See the discussion at https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2465.


Get Started

Remember this is a beta release and there may be small breaking changes before the stable release.

Leave your comments below.

5 Likes

2 posts were split to a new topic: How to implement ERC721 batchBuy

Note that while it is indeed ‘the end of the SafeMath era’, there are still cases in which developers would want to avoid using the (now safe) arithmetic operators, by encapsulating their designated piece of code within an unchecked clause, where cheaper (unsafe) arithmetic is applied instead.
For example, when implementing an efficient non-integer-exponentiation.
There are simpler examples, like binary log, square root, and in fact - every arithmetic computation in your code which you’ve implemented without using SafeMath because you knew that it was inherently safe. Even the simplest for loop with a 256-bit counter which would never overflow, now becomes more expensive as a result of the ++ operator being safe.
There’s a fair chance that many developers would just put their entire code under unchecked, while continuing to use SafeMath where necessary (i.e., wherever it is used in “close proximity” with natural arithmetic, and it is easier to just use it rather than “toggling” the unchecked option over and over).
In that sense, it is debatable that this new feature of Solc 0.8 is a pure advantage.

1 Like

I agree it is debatable and I hope it’s a debate we have together with the Solidity team in order to push the language forward toward cheaper and safer patterns.

In the meantime, using unchecked + SafeMath sounds like a reasonable alternative an it’s one of the reasons the SafeMath library is still included in 4.0.

2 Likes

4.0.0-beta.1 update

We just released the second preview of Contracts 4.0. This update includes some changes that have been requested by users. Some gas optimizations are also included.

Changes

ERC20

The ERC20Capped extensions now enforces the check directly in the _mint function, thus removing the addition gas cost this extension used to have on transfers.

ERC721

A new extension, ERC721URIStorage re-implements the tokenURI mechanism that used to be part of the simple ERC721 implementation in the 3.x releases. In particular, this includes the internal _setTokenURI method that allows for custom URIs.

ERC777

Optimization of the constructor gas cost for the ERC777.

Proxy

proxy/UpgradeableProxy has been moved and renamed to proxy/ERC1967/ERC1967Proxy.sol. This is done to prepare the path to more proxy patterns such as ERC1822’s UUPS.

Get Started

Remember this is a beta release and there may be small breaking changes before the stable release.

Leave your comments below.

1 Like

A post was split to a new topic: Is it safe to upgrade from OpenZeppelin Contracts Upgradeable 3.4.0 to 4.0.0

4.0.0-rc.0 update

The release candidate for 4.0 is out. We hope to release it officially during the 4th week of March.

1 Like

4.0.0 is out :rocket:

1 Like

A post was split to a new topic: Using ETHless meta-txs