// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

/// @title EIP712BaseV3
/// @notice EIP-712 domain separator with correct chain-id rebinding on fork.
/// @dev  Domain: name="Vaultfire", version=protocolVersion (e.g. "3.0.0"),
///       chainId, verifyingContract. The separator is calculated from the
///       current chain and contract address rather than cached as an immutable:
///       caching it would embed each freshly-created child's address into its
///       runtime bytecode and make a single reviewed child runtime hash unusable
///       for more than one otherwise identical deployment.
abstract contract EIP712BaseV3 {
    bytes32 private constant _TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
    bytes32 private constant _NAME_HASH = keccak256(bytes("Vaultfire"));

    bytes32 private immutable _VERSION_HASH;

    constructor(string memory protocolVersion) {
        _VERSION_HASH = keccak256(bytes(protocolVersion));
    }

    function _domainSeparator() internal view returns (bytes32) {
        return _buildDomainSeparator();
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(_TYPE_HASH, _NAME_HASH, _VERSION_HASH, block.chainid, address(this)));
    }

    function _hashTypedData(bytes32 structHash) internal view returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", _domainSeparator(), structHash));
    }

    function DOMAIN_SEPARATOR() external view returns (bytes32) {
        return _domainSeparator();
    }
}
