@@ -16,20 +16,40 @@ abstract contract EIP712 {
1616
1717 address private immutable _cachedThis;
1818 uint256 private immutable _cachedChainId;
19+ bytes32 private immutable _cachedNameHash;
20+ bytes32 private immutable _cachedVersionHash;
1921 bytes32 private immutable _cachedDomainSeparator;
2022
2123 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
2224 /* CONSTRUCTOR */
2325 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
2426
25- /// @dev Cache the domain separator for cheaper runtime gas costs in
26- /// non-upgradeable contracts. In the case of upgradeable contracts
27- /// (i.e. proxies), or if the chain id changes due to a hard fork,
27+ /// @dev Cache the hashes for cheaper runtime gas costs.
28+ /// In the case of upgradeable contracts (i.e. proxies),
29+ /// or if the chain id changes due to a hard fork,
2830 /// the domain separator will be seamlessly calculated on-the-fly.
2931 constructor () {
3032 _cachedThis = address (this );
3133 _cachedChainId = block .chainid ;
32- _cachedDomainSeparator = _buildDomainSeparator ();
34+
35+ (string memory name , string memory version ) = _domainNameAndVersion ();
36+ bytes32 nameHash = keccak256 (bytes (name));
37+ bytes32 versionHash = keccak256 (bytes (version));
38+ _cachedNameHash = nameHash;
39+ _cachedVersionHash = versionHash;
40+
41+ bytes32 separator;
42+ /// @solidity memory-safe-assembly
43+ assembly {
44+ let m := mload (0x40 ) // Load the free memory pointer.
45+ mstore (m, _DOMAIN_TYPEHASH)
46+ mstore (add (m, 0x20 ), nameHash)
47+ mstore (add (m, 0x40 ), versionHash)
48+ mstore (add (m, 0x60 ), chainid ())
49+ mstore (add (m, 0x80 ), address ())
50+ separator := keccak256 (m, 0xa0 )
51+ }
52+ _cachedDomainSeparator = separator;
3353 }
3454
3555 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
@@ -54,31 +74,6 @@ abstract contract EIP712 {
5474 virtual
5575 returns (string memory name , string memory version );
5676
57- /// @dev You may override this function to directly return the `nameHash`
58- /// and the `versionHash` for gas savings if the domain separator has to be
59- /// computed on-the-fly (in upgradeable contracts, or if chain id changes).
60- /// ```
61- /// function _domainNameAndVersionHashes()
62- /// internal
63- /// pure
64- /// virtual
65- /// returns (bytes32 nameHash, bytes32 versionHash)
66- /// {
67- /// nameHash = keccak256(bytes("Solady"));
68- /// versionHash = keccak256(bytes("1"));
69- /// }
70- /// ```
71- function _domainNameAndVersionHashes ()
72- internal
73- pure
74- virtual
75- returns (bytes32 nameHash , bytes32 versionHash )
76- {
77- (string memory name , string memory version ) = _domainNameAndVersion ();
78- nameHash = keccak256 (bytes (name));
79- versionHash = keccak256 (bytes (version));
80- }
81-
8277 /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
8378 /* HASHING OPERATIONS */
8479 /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
@@ -154,7 +149,8 @@ abstract contract EIP712 {
154149
155150 /// @dev Returns the EIP-712 domain separator.
156151 function _buildDomainSeparator () private view returns (bytes32 separator ) {
157- (bytes32 nameHash , bytes32 versionHash ) = _domainNameAndVersionHashes ();
152+ bytes32 nameHash = _cachedNameHash;
153+ bytes32 versionHash = _cachedVersionHash;
158154 /// @solidity memory-safe-assembly
159155 assembly {
160156 let m := mload (0x40 ) // Load the free memory pointer.
0 commit comments