pub fn construct_eip712_message_hash(
request: &SignTypedDataRequest,
) -> Result<[u8; 32], SignerError>Expand description
Constructs an EIP-712 message hash from domain separator and struct hash
This function implements the EIP-712 typed data signing specification: https://eips.ethereum.org/EIPS/eip-712
§EIP-712 Format
The message hash is constructed as:
keccak256("\x19\x01" ‖ domainSeparator ‖ hashStruct(message))§Security Considerations
CRITICAL SECURITY REQUIREMENTS:
-
Domain Separator Uniqueness: The domain separator MUST be unique to your dapp to prevent cross-contract replay attacks. Include at minimum:
- Contract name
- Contract version
- Chain ID (prevents cross-chain replays)
- Verifying contract address
-
Hash Struct Integrity: The hashStruct MUST uniquely identify your message type and data. Collisions allow signature reuse across different messages.
-
Replay Protection: Always include nonces or timestamps in your message struct to prevent replay attacks within the same contract.
-
Chain ID: MUST be included in domain separator to prevent signatures from being valid on multiple chains (mainnet, testnet, etc.)
§Arguments
request- The typed data signing request containing:domain_separator: 32-byte hash uniquely identifying the signing domainhash_struct_message: 32-byte hash of the structured message data
§Returns
Ok([u8; 32])- The 32-byte message hash ready for signingErr(SignerError)- If validation fails or hex decoding fails
§Errors
Returns SignerError::SigningError if:
- Domain separator is not exactly 32 bytes
- Hash struct is not exactly 32 bytes
- Input contains invalid hexadecimal characters
§Examples
use crate::domain::SignTypedDataRequest;
use crate::services::signer::evm::construct_eip712_message_hash;
let request = SignTypedDataRequest {
// 32 bytes as hex (with or without 0x prefix)
domain_separator: "a".repeat(64),
hash_struct_message: "b".repeat(64),
};
let hash = construct_eip712_message_hash(&request)?;
// hash is now ready for signing