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.
0x66c1d6f22263b067be80ff923fbd14dbb34444665d3e6eaa781be5b5ef72c6b1Order(address maker,uint8 side,Asset asset,Asset[] fees,uint256 deadline,bytes32 salt)Asset(address token,uint256 id)0x6c86d7b746dab1eb0645fc67158b8b45b7c55c0594bda96e733e1fceb6435195bytes32 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