EIP-712

Hashing & encoding

EIP-712 typehash & hasher

Paste Solidity structs or eth_signTypedData_v4 JSON and get the EIP-712 encodeType string, every typehash, the domain separator, struct hash and final digest, plus ready-to-paste Solidity that hashes nested structs and arrays exactly like the wallet does.

try
typehashes
Order typehash
0x66c1d6f22263b067be80ff923fbd14dbb34444665d3e6eaa781be5b5ef72c6b1
encodeType: the exact string that gets hashed
Order(address maker,uint8 side,Asset asset,Asset[] fees,uint256 deadline,bytes32 salt)Asset(address token,uint256 id)
Asset typehash
0x6c86d7b746dab1eb0645fc67158b8b45b7c55c0594bda96e733e1fceb6435195
solidity: typehash constants + hash functions
bytes32 constant ORDER_TYPEHASH = keccak256("Order(address maker,uint8 side,Asset asset,Asset[] fees,uint256 deadline,bytes32 salt)Asset(address token,uint256 id)"); bytes32 constant ASSET_TYPEHASH = keccak256("Asset(address token,uint256 id)"); function _hashOrder(Order memory _order) internal pure returns (bytes32) { return keccak256( abi.encode( ORDER_TYPEHASH, _order.maker, _order.side, _hashAsset(_order.asset), _hashAssetArray(_order.fees), _order.deadline, _order.salt ) ); } function _hashAsset(Asset memory asset) internal pure returns (bytes32) { return keccak256(abi.encode(ASSET_TYPEHASH, asset.token, asset.id)); } function _hashAssetArray(Asset[] memory items) internal pure returns (bytes32) { bytes32[] memory hashes = new bytes32[](items.length); for (uint256 i; i < items.length; ++i) hashes[i] = _hashAsset(items[i]); return keccak256(abi.encodePacked(hashes)); }matches eth_signTypedData_v4. feed the result to _hashTypedDataV4() from openzeppelin's EIP712

good to know

why does my signature not verify on-chain?

almost always a typehash mismatch: the encodeType string must list fields in declaration order with canonical types (uint256, not uint), no spaces after commas, and every referenced struct appended in alphabetical order. copy the string from here instead of typing it.

how are arrays and nested structs hashed?

a nested struct is replaced by its own struct hash. an array becomes keccak256 of its elements’ encodings concatenated: 32-byte values as they are, strings and bytes as their keccak256, structs as their struct hashes.

how do enums show up?

as uint8. eip-712 has no enum type, and solidity abi-encodes enums as uint8.