Utilities

Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives.

  • Masks: Library to handle bytes32 masks.

  • ERC7739Utils: Utilities library that implements a defensive rehashing mechanism to prevent replayability of smart contract signatures based on ERC-7739.

  • ERC7739Signer: An abstract contract to validate signatures following the rehashing scheme from ERC7739Utils.

Cryptography

ERC7739Signer

import "@openzeppelin/contracts/utils/cryptography/draft-ERC7739Signer.sol";

Validates signatures wrapping the message hash in a nested EIP712 type. See ERC7739Utils.

Linking the signature to the EIP-712 domain separator is a security measure to prevent signature replay across different EIP-712 domains (e.g. a single offchain owner of multiple contracts).

This contract requires implementing the _validateSignature function, which passes the wrapped message hash, which may be either an typed data or a personal sign nested type.

{EIP712} uses {ShortStrings} to optimize gas costs for short strings (up to 31 characters). Consider that strings longer than that will use storage, which may limit the ability of the signer to be used within the ERC-4337 validation phase (due to ERC-7562 storage access rules).
Functions
  • isValidSignature(hash, signature)

  • _isValidSignature(hash, signature)

  • _isValidNestedPersonalSignSignature(hash, signature)

  • _isValidNestedTypedDataSignature(hash, encodedSignature)

  • _validateSignature(hash, signature)

EIP712
  • _domainSeparatorV4()

  • _hashTypedDataV4(structHash)

  • eip712Domain()

  • _EIP712Name()

  • _EIP712Version()

Events
IERC5267
  • EIP712DomainChanged()

isValidSignature(bytes32 hash, bytes signature) → bytes4 result public

Attempts validating the signature in a nested EIP-712 type.

A nested EIP-712 type might be presented in 2 different ways:

  • As a nested EIP-712 typed data

  • As a personal signature (an EIP-712 mimic of the eth_personalSign for a smart contract)

_isValidSignature(bytes32 hash, bytes signature) → bool internal

Internal version of isValidSignature that returns a boolean.

_isValidNestedPersonalSignSignature(bytes32 hash, bytes signature) → bool internal

Nested personal signature verification.

_isValidNestedTypedDataSignature(bytes32 hash, bytes encodedSignature) → bool internal

Nested EIP-712 typed data verification.

_validateSignature(bytes32 hash, bytes signature) → bool internal

Signature validation algorithm.

Implementing a signature validation algorithm is a security-sensitive operation as it involves cryptographic verification. It is important to review and test thoroughly before deployment. Consider using one of the signature verification libraries ({ECDSA}, {P256} or {RSA}).

ERC7739Utils

import "@openzeppelin/contracts/utils/cryptography/draft-ERC7739Utils.sol";

Utilities to process ERC-7739 typed data signatures that are specific to an EIP-712 domain.

This library provides methods to wrap, unwrap and operate over typed data signatures with a defensive rehashing mechanism that includes the application’s {EIP712-_domainSeparatorV4} and preserves readability of the signed content using an EIP-712 nested approach.

A smart contract domain can validate a signature for a typed data structure in two ways:

  • As an application validating a typed data signature. See {toNestedTypedDataHash}.

  • As a smart contract validating a raw message signature. See {toNestedPersonalSignHash}.

A provider for a smart contract wallet would need to return this signature as the result of a call to personal_sign or eth_signTypedData, and this may be unsupported by API clients that expect a return value of 129 bytes, or specifically the r,s,v parameters of an {ECDSA} signature, as is for example specified for {EIP712}.
Functions
  • encodeTypedDataSig(signature, appSeparator, contentsHash, contentsDescr)

  • decodeTypedDataSig(encodedSignature)

  • personalSignStructHash(contents)

  • typedDataSignStructHash(contentsTypeName, contentsType, contentsHash, domainBytes)

  • typedDataSignStructHash(contentsDescr, contentsHash, domainBytes)

  • typedDataSignTypehash(contentsTypeName, contentsType)

  • decodeContentsDescr(contentsDescr)

Errors
  • InvalidContentsType()

encodeTypedDataSig(bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescr) → bytes internal

Nest a signature for a given EIP-712 type into a nested signature for the domain of the app.

Counterpart of decodeTypedDataSig to extract the original signature and the nested components.

decodeTypedDataSig(bytes encodedSignature) → bytes signature, bytes32 appSeparator, bytes32 contentsHash, string contentsDescr internal

Parses a nested signature into its components.

Constructed as follows:

signature ‖ DOMAIN_SEPARATOR ‖ contentsHash ‖ contentsDescr ‖ uint16(contentsDescr.length)

  • signature is the original signature for the nested struct hash that includes the "contents" hash

  • DOMAIN_SEPARATOR is the EIP-712 {EIP712-_domainSeparatorV4} of the smart contract verifying the signature

  • contentsHash is the hash of the underlying data structure or message

  • contentsDescr is a descriptor of the "contents" part of the the EIP-712 type of the nested signature

personalSignStructHash(bytes32 contents) → bytes32 internal

Nests an ERC-191 digest into a PersonalSign EIP-712 struct, and return the corresponding struct hash. This struct hash must be combined with a domain separator, using {MessageHashUtils-toTypedDataHash} before being verified/recovered.

This is used to simulates the personal_sign RPC method in the context of smart contracts.

typedDataSignStructHash(string contentsTypeName, string contentsType, bytes32 contentsHash, bytes domainBytes) → bytes32 result internal

Nests an EIP-712 hash (contents) into a TypedDataSign EIP-712 struct, and return the corresponding struct hash. This struct hash must be combined with a domain separator, using {MessageHashUtils-toTypedDataHash} before being verified/recovered.

typedDataSignStructHash(string contentsDescr, bytes32 contentsHash, bytes domainBytes) → bytes32 result internal

Variant of {typedDataSignStructHash-string-string-bytes32-string-bytes} that takes a content descriptor and decodes the contentsTypeName and contentsType out of it.

typedDataSignTypehash(string contentsTypeName, string contentsType) → bytes32 internal

Compute the EIP-712 typehash of the TypedDataSign structure for a given type (and typename).

decodeContentsDescr(string contentsDescr) → string contentsTypeName, string contentsType internal

Parse the type name out of the ERC-7739 contents type description. Supports both the implicit and explicit modes.

Following ERC-7739 specifications, a contentsTypeName is considered invalid if it’s empty or it contains any of the following bytes , )\x00

If the contentsType is invalid, this returns an empty string. Otherwise, the return string has non-zero length.

InvalidContentsType() error

Error when the contents type is invalid. See {tryValidateContentsType}.

Libraries

Masks

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

Library for handling bit masks

Functions
  • toMask(group)

  • toMask(groups)

  • get(self, group)

  • isEmpty(self)

  • complement(m1)

  • union(m1, m2)

  • intersection(m1, m2)

  • difference(m1, m2)

  • symmetric_difference(m1, m2)

toMask(uint8 group) → Masks.Mask internal

Returns a new mask with the bit at group index set to 1.

toMask(uint8[] groups) → Masks.Mask internal

Returns a new mask with the bits at groups indices set to 1.

get(Masks.Mask self, uint8 group) → bool internal

Get value of the mask at group index

isEmpty(Masks.Mask self) → bool internal

Whether the mask is bytes32(0)

complement(Masks.Mask m1) → Masks.Mask internal

Invert the bits of a mask

union(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal

Perform a bitwise OR operation on two masks

intersection(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal

Perform a bitwise AND operation on two masks

difference(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal

Perform a bitwise difference operation on two masks (m1 - m2)

symmetric_difference(Masks.Mask m1, Masks.Mask m2) → Masks.Mask internal

Returns the symmetric difference (∆) of two masks, also known as disjunctive union or exclusive OR (XOR)