Utilities

The OpenZeppelin Contracts provide a ton of useful utilities that you can use in your project. Here are some of the more popular ones.

Cryptography

Checking Signatures On-Chain

ECDSA provides functions for recovering and managing Ethereum account ECDSA signatures. These are often generated via web3.eth.sign, and are a 65 byte array (of type bytes in Solidity) arranged the following way: [[v (1)], [r (32)], [s (32)]].

The data signer can be recovered with ECDSA.recover, and its address compared to verify the signature. Most wallets will hash the data to sign and add the prefix '\x19Ethereum Signed Message:\n', so when attempting to recover the signer of an Ethereum signed message hash, you’ll want to use toEthSignedMessageHash.

using ECDSA for bytes32;
using MessageHashUtils for bytes32;

function _verify(bytes32 data, bytes memory signature, address account) internal pure returns (bool) {
    return data
        .toEthSignedMessageHash()
        .recover(signature) == account;
}
Getting signature verification right is not trivial: make sure you fully read and understand MessageHashUtils's and ECDSA's documentation.

Verifying Merkle Proofs

MerkleProof provides:

Introspection

In Solidity, it’s frequently helpful to know whether or not a contract supports an interface you’d like to use. ERC165 is a standard that helps do runtime interface detection. Contracts provide helpers both for implementing ERC165 in your contracts and querying other contracts:

contract MyContract {
    using ERC165Checker for address;

    bytes4 private InterfaceId_ERC721 = 0x80ac58cd;

    /**
     * @dev transfer an ERC721 token from this contract to someone else
     */
    function transferERC721(
        address token,
        address to,
        uint256 tokenId
    )
        public
    {
        require(token.supportsInterface(InterfaceId_ERC721), "IS_NOT_721_TOKEN");
        IERC721(token).transferFrom(address(this), to, tokenId);
    }
}

Math

Although Solidity already provides math operators (i.e. +, -, etc.), Contracts includes Math; a set of utilities for dealing with mathematical operators, with support for extra operations (eg. average) and SignedMath; a library specialized in signed math operations.

Include these contracts with using Math for uint256 or using SignedMath for int256 and then use their functions in your code:

contract MyContract {
    using Math for uint256;
    using SignedMath for int256;

    function tryOperations(uint256 a, uint256 b) internal pure {
        (bool overflowsAdd, uint256 resultAdd) = x.tryAdd(y);
        (bool overflowsSub, uint256 resultSub) = x.trySub(y);
        (bool overflowsMul, uint256 resultMul) = x.tryMul(y);
        (bool overflowsDiv, uint256 resultDiv) = x.tryDiv(y);
        // ...
    }

    function unsignedAverage(int256 a, int256 b) {
        int256 avg = a.average(b);
        // ...
    }
}

Easy!

Structures

Some use cases require more powerful data structures than arrays and mappings offered natively in Solidity. Contracts provides these libraries for enhanced data structure management:

The Enumerable* structures are similar to mappings in that they store and remove elements in constant time and don’t allow for repeated entries, but they also support enumeration, which means you can easily query all stored entries both on and off-chain.

Misc

Base64

Base64 util allows you to transform bytes32 data into its Base64 string representation.

This is especially useful for building URL-safe tokenURIs for both ERC721 or ERC1155. This library provides a clever way to serve URL-safe Data URI compliant strings to serve on-chain data structures.

Here is an example to send JSON Metadata through a Base64 Data URI using an ERC721:

// contracts/My721Token.sol
// SPDX-License-Identifier: MIT

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";

contract My721Token is ERC721 {
    using Strings for uint256;

    constructor() ERC721("My721Token", "MTK") {}

    ...

    function tokenURI(uint256 tokenId)
        public
        pure
        override
        returns (string memory)
    {
        bytes memory dataURI = abi.encodePacked(
            '{',
                '"name": "My721Token #', tokenId.toString(), '"',
                // Replace with extra ERC721 Metadata properties
            '}'
        );

        return string(
            abi.encodePacked(
                "data:application/json;base64,",
                Base64.encode(dataURI)
            )
        );
    }
}

Multicall

The Multicall abstract contract comes with a multicall function that bundles together multiple calls in a single external call. With it, external accounts may perform atomic operations comprising several function calls. This is not only useful for EOAs to make multiple calls in a single transaction, it’s also a way to revert a previous call if a later one fails.

Consider this dummy contract:

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/utils/Multicall.sol";

contract Box is Multicall {
    function foo() public {
        ...
    }

    function bar() public {
        ...
    }
}

This is how to call the multicall function using Truffle, allowing foo and bar to be called in a single transaction:

// scripts/foobar.js

const Box = artifacts.require('Box');
const instance = await Box.new();

await instance.multicall([
    instance.contract.methods.foo().encodeABI(),
    instance.contract.methods.bar().encodeABI()
]);