# EIP-712 type hashing in Solidity tests

Description: How to use EIP-712 type hashing cheatcodes in Solidity tests

Note: This document was authored using MDX

  Source: https://github.com/NomicFoundation/hardhat-website/tree/main/src/content/docs/docs/guides/testing/eip712-types.mdx

Hardhat provides three cheatcodes for EIP-712 hashing in Solidity tests:

- [`eip712HashType`](/docs/reference/cheatcodes/utilities/eip712-hash-type)
- [`eip712HashStruct`](/docs/reference/cheatcodes/utilities/eip712-hash-struct)
- [`eip712HashTypedData`](/docs/reference/cheatcodes/utilities/eip712-hash-typed-data)

The first two look up your project's struct definitions by name, avoiding hand-written canonical type strings. `eip712HashTypedData` computes a digest from a self-describing JSON payload and works without any configuration.

## Configuration

`eip712HashType` and `eip712HashStruct` need a registry of struct types to resolve names. Enable this by adding an `eip712Types` block to your `hardhat.config.ts`:

```ts
// hardhat.config.ts
import { defineConfig } from "hardhat/config";

export default defineConfig({
  test: {
    solidity: {
      eip712Types: {
        include: ["contracts/**", "test/contracts/**"],
        // exclude: ["contracts/legacy/**"], // Optional
      },
    },
  },
});
```

> **Note:** To include structs from npm packages, match against the input source name used by solc (e.g. `"npm/@uniswap/permit2@*/src/interfaces/ISignatureTransfer.sol"`). For the full reference, see [Solidity tests configuration](/docs/reference/configuration#solidity-tests-configuration).

## Example

If your bundled `forge-std` doesn't expose these cheatcodes on its `vm` interface yet, declare a local interface and call them through the cheatcode address.

Given these struct definitions in `contracts/Eip712Types.sol`:

```solidity
struct Person {
  address wallet;
  string name;
}

struct Mail {
  Person from;
  Person to;
  string contents;
}
```

You can hash types and structs in your tests:

```solidity
import "forge-std/Test.sol";
import "../../contracts/Eip712Types.sol";

interface IEip712Cheats {
  function eip712HashType(string calldata) external pure returns (bytes32);
  function eip712HashStruct(
    string calldata,
    bytes calldata
  ) external pure returns (bytes32);
  function eip712HashTypedData(string calldata) external pure returns (bytes32);
}

contract Eip712Test is Test {
  IEip712Cheats cheats = IEip712Cheats(address(vm));

  function testMailTypeHash() public {
    bytes32 expected = keccak256(
      bytes(
        "Mail(Person from,Person to,string contents)"
        "Person(address wallet,string name)"
      )
    );
    assertEq(cheats.eip712HashType("Mail"), expected);
  }

  function testMailStructHash() public {
    Mail memory m = Mail({
      from: Person({ wallet: address(0xA), name: "Alice" }),
      to: Person({ wallet: address(0xB), name: "Bob" }),
      contents: "hello"
    });

    bytes32 hash = cheats.eip712HashStruct("Mail", abi.encode(m));
    // hash now equals the standard EIP-712 struct hash for `m`.
  }
}
```

## Duplicate struct names

Each struct name must map to exactly one definition across the collected set. If two different structs share a name, the test run fails with error `HHE818`. To fix this, rename one of the structs or narrow your `include`/`exclude` globs. Identical definitions across multiple build infos are deduplicated silently.
