@@ -26,6 +26,16 @@ abstract contract EIP712 {
2626 bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID =
2727 0x91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a2766 ;
2828
29+ /// @dev `keccak256("EIP712Domain(string name,string version)")`.
30+ /// This is only used in `_hashTypedDataSansChainIdAndVerifyingContract`.
31+ bytes32 internal constant _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT =
32+ 0xb03948446334eb9b2196d5eb166f69b9d49403eb4a12f36de8d3f9f3cb8e15c3 ;
33+
34+ /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId)")`.
35+ /// This is only used in `_hashTypedDataSansVerifyingContract`.
36+ bytes32 internal constant _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT =
37+ 0xc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e ;
38+
2939 uint256 private immutable _cachedThis;
3040 uint256 private immutable _cachedChainId;
3141 bytes32 private immutable _cachedNameHash;
@@ -147,9 +157,7 @@ abstract contract EIP712 {
147157 }
148158
149159 /// @dev Variant of `_hashTypedData` that excludes the chain ID.
150- /// We expect that most contracts will use `_hashTypedData` as the main hash,
151- /// and `_hashTypedDataSansChainId` only occasionally for cross-chain workflows.
152- /// Thus this is optimized for smaller bytecode size over runtime gas.
160+ /// Included for the niche use case of cross-chain workflows.
153161 function _hashTypedDataSansChainId (bytes32 structHash )
154162 internal
155163 view
@@ -174,6 +182,57 @@ abstract contract EIP712 {
174182 }
175183 }
176184
185+ /// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
186+ /// Included for the niche use case of cross-chain and multi-verifier workflows.
187+ function _hashTypedDataSansChainIdAndVerifyingContract (bytes32 structHash )
188+ internal
189+ view
190+ virtual
191+ returns (bytes32 digest )
192+ {
193+ (string memory name , string memory version ) = _domainNameAndVersion ();
194+ /// @solidity memory-safe-assembly
195+ assembly {
196+ let m := mload (0x40 ) // Load the free memory pointer.
197+ mstore (0x00 , _DOMAIN_TYPEHASH_SANS_CHAIN_ID_AND_VERIFYING_CONTRACT)
198+ mstore (0x20 , keccak256 (add (name, 0x20 ), mload (name)))
199+ mstore (0x40 , keccak256 (add (version, 0x20 ), mload (version)))
200+ // Compute the digest.
201+ mstore (0x20 , keccak256 (0x00 , 0x60 )) // Store the domain separator.
202+ mstore (0x00 , 0x1901 ) // Store "\x19\x01".
203+ mstore (0x40 , structHash) // Store the struct hash.
204+ digest := keccak256 (0x1e , 0x42 )
205+ mstore (0x40 , m) // Restore the free memory pointer.
206+ mstore (0x60 , 0 ) // Restore the zero pointer.
207+ }
208+ }
209+
210+ /// @dev Variant of `_hashTypedData` that excludes the chain ID and verifying contract.
211+ /// Included for the niche use case of multi-verifier workflows.
212+ function _hashTypedDataSansVerifyingContract (bytes32 structHash )
213+ internal
214+ view
215+ virtual
216+ returns (bytes32 digest )
217+ {
218+ (string memory name , string memory version ) = _domainNameAndVersion ();
219+ /// @solidity memory-safe-assembly
220+ assembly {
221+ let m := mload (0x40 ) // Load the free memory pointer.
222+ mstore (0x00 , _DOMAIN_TYPEHASH_SANS_VERIFYING_CONTRACT)
223+ mstore (0x20 , keccak256 (add (name, 0x20 ), mload (name)))
224+ mstore (0x40 , keccak256 (add (version, 0x20 ), mload (version)))
225+ mstore (0x60 , chainid ())
226+ // Compute the digest.
227+ mstore (0x20 , keccak256 (0x00 , 0x80 )) // Store the domain separator.
228+ mstore (0x00 , 0x1901 ) // Store "\x19\x01".
229+ mstore (0x40 , structHash) // Store the struct hash.
230+ digest := keccak256 (0x1e , 0x42 )
231+ mstore (0x40 , m) // Restore the free memory pointer.
232+ mstore (0x60 , 0 ) // Restore the zero pointer.
233+ }
234+ }
235+
177236 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
178237 /* EIP-5267 OPERATIONS */
179238 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
0 commit comments