Openzeppelin Contracts v4 in Review

Taking a look at the new Openzeppelin v4 Release

The Openzeppelin v4 contracts are now available in Beta and most notably come with Solidity 0.8 support. For older compiler versions, you'll need to stick with the older contract versions. The beta tag means there still might be small breaking changes coming for the final v4 version, but you can already checkout the release at the repo with the full Changelog available here.

Matryoshka

1. Standardized Meta Transactions Support

First of we have support for EIP-2771 meta transactions. We have discussed meta transactions previously here. The Openzeppelin contracts are slightly less powerful than our implementation in the referenced blog post, but nonetheless they are a great start for a minimal setup and they also support the new EIP-2771 standard for meta transactions.

What is EIP-2771? In this meta transaction design there is a new contract: a trusted forwarder contract. The main idea behind it is having a consistent msg.sender. As you may already know, when sending a meta transaction, someone else pays the gas costs for the actual signer. This so called relayer will submit the transaction to the contract, but this also means the msg.sender will actually be the address of the relayer.

To solve this, EIP-2771 proposes a forwarder contract. This forwarder will take the original call from the relayer, verify a valid signature, append the msg.data with the signer address, check there's enough gas left for the call (security critical) and then execute the requested call to the destination. This forwarder is available via the MinimalForwarder.sol.

The destination will be a recipient contract which implements an additional:

function isTrustedForwarder(address forwarder) public returns(bool);

where the forwarder is an approved forwarder contract. Now first the recipient can check if the contract is a trusted forwarder. If that's the case it can extract the msg.sender from the end of the msg.data and use it as the actual msg.sender. The recipient is available via the ERC2771Context.sol.

So the way you would use this in your contracts would be something like

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import "@openzeppelin/contracts/metatx/MinimalForwarder.sol";

contract MetaTxReceiverExample is ERC2771Context {
    constructor(address trustedForwarder) ERC2771Context(trustedForwarder) {}

    function exampleFunction(uint256 amount) external {
        (bool success, ) = _msgSender().call{ value: amount }("");
        require(success, "Transfer failed.");
    }
}

contract MyMinimalForwarder is MinimalForwarder {}

Now you can deploy MyMinimalForwarder and then MetaTxReceiverExample, setting the trustedForwarder to the previously deployed contract. Users can now either directly call exampleFunction and pay the gas themselves, or they can create a meta transaction, send it to a relayer which then calls execute on MyMinimalForwarder which will forward the call to the MetaTxReceiverExample contract.

2. Reduced Gas Costs for Berlin

Second of all, the gas costs have been improved in several places. This was done, because obviously gas costs have been incredibly high again, but also due to the upcoming Berlin hard fork. This hard fork will come with increased gas costs for state access opcodes (EIP-2929).

The gas improvements include:

  • ERC20: Removed the extra decimals storage variable. Now has to be used by overriding the function.
  • ERC165: Removed the extra mapping variable holding supported interfaces. Now has to be used by overriding the function.
  • ERC721 Enumerability and URIs: Enumerability was removed as default, see 721 post here.
  • AccessControl: Removed enumerability as default.
ETH Berlin

3. Is SafeMath removed?

xkcd updates

Obviously the SafeMath library is not really required anymore with Solidity 0.8, but it's actually still present. Why is that?

It is now just a wrapper over the built-in overflow checks. The library was kept to ease the transition, but everyone is encouraged to remove SafeMath from their contracts and rely on the compiler checks exclusively. As a matter of fact, SafeMath may be fully removed in a future major release. For full discussion of this issue see here.

4. Reorganized Repository

Many files in the repo were moved to new places. This was done to make it easier to find new functionality more intuitively. If you're coming from a previous contracts release, make sure to update the import paths accordingly.

The Stable v4 Release

This was a peak into the new version. Keep in mind this is not audited code and also still in Beta, but according to the timeline should have its proper release very shortly. So I wouldn't expect any major changes to come up anymore.

Let me know if you are also using the Openzeppelin contracts regularly. And if you are already actively using Solidity 0.8?


Markus Waas

Solidity Developer

More great blog posts from Markus Waas

© 2024 Solidity Dev Studio. All rights reserved.

This website is powered by Scrivito, the next generation React CMS.