Include EIP-5267 discovery in EIP-712 (#3969)
Co-authored-by: Francisco <frangio.1@gmail.com> Co-authored-by: Francisco <fg@frang.io>
This commit is contained in:
@ -1,9 +1,11 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
pragma solidity ^0.8.8;
|
||||
|
||||
import "./ECDSA.sol";
|
||||
import "../ShortStrings.sol";
|
||||
import "../../interfaces/IERC5267.sol";
|
||||
|
||||
/**
|
||||
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
|
||||
@ -22,19 +24,34 @@ import "./ECDSA.sol";
|
||||
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
|
||||
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
|
||||
*
|
||||
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
|
||||
* separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
|
||||
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
|
||||
*
|
||||
* _Available since v3.4._
|
||||
*
|
||||
* @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
|
||||
*/
|
||||
abstract contract EIP712 {
|
||||
abstract contract EIP712 is IERC5267 {
|
||||
using ShortStrings for *;
|
||||
|
||||
bytes32 private constant _TYPE_HASH =
|
||||
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
|
||||
|
||||
/* solhint-disable var-name-mixedcase */
|
||||
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
|
||||
// invalidate the cached domain separator if the chain id changes.
|
||||
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
|
||||
uint256 private immutable _CACHED_CHAIN_ID;
|
||||
address private immutable _CACHED_THIS;
|
||||
bytes32 private immutable _cachedDomainSeparator;
|
||||
uint256 private immutable _cachedChainId;
|
||||
address private immutable _cachedThis;
|
||||
|
||||
bytes32 private immutable _HASHED_NAME;
|
||||
bytes32 private immutable _HASHED_VERSION;
|
||||
bytes32 private immutable _TYPE_HASH;
|
||||
ShortString private immutable _name;
|
||||
ShortString private immutable _version;
|
||||
string private _nameFallback;
|
||||
string private _versionFallback;
|
||||
|
||||
bytes32 private immutable _hashedName;
|
||||
bytes32 private immutable _hashedVersion;
|
||||
|
||||
/* solhint-enable var-name-mixedcase */
|
||||
|
||||
@ -51,36 +68,29 @@ abstract contract EIP712 {
|
||||
* contract upgrade].
|
||||
*/
|
||||
constructor(string memory name, string memory version) {
|
||||
bytes32 hashedName = keccak256(bytes(name));
|
||||
bytes32 hashedVersion = keccak256(bytes(version));
|
||||
bytes32 typeHash = keccak256(
|
||||
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
|
||||
);
|
||||
_HASHED_NAME = hashedName;
|
||||
_HASHED_VERSION = hashedVersion;
|
||||
_CACHED_CHAIN_ID = block.chainid;
|
||||
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
|
||||
_CACHED_THIS = address(this);
|
||||
_TYPE_HASH = typeHash;
|
||||
_name = name.toShortStringWithFallback(_nameFallback);
|
||||
_version = version.toShortStringWithFallback(_versionFallback);
|
||||
_hashedName = keccak256(bytes(name));
|
||||
_hashedVersion = keccak256(bytes(version));
|
||||
|
||||
_cachedChainId = block.chainid;
|
||||
_cachedDomainSeparator = _buildDomainSeparator();
|
||||
_cachedThis = address(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Returns the domain separator for the current chain.
|
||||
*/
|
||||
function _domainSeparatorV4() internal view returns (bytes32) {
|
||||
if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
|
||||
return _CACHED_DOMAIN_SEPARATOR;
|
||||
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
|
||||
return _cachedDomainSeparator;
|
||||
} else {
|
||||
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
|
||||
return _buildDomainSeparator();
|
||||
}
|
||||
}
|
||||
|
||||
function _buildDomainSeparator(
|
||||
bytes32 typeHash,
|
||||
bytes32 nameHash,
|
||||
bytes32 versionHash
|
||||
) private view returns (bytes32) {
|
||||
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
|
||||
function _buildDomainSeparator() private view returns (bytes32) {
|
||||
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,4 +111,33 @@ abstract contract EIP712 {
|
||||
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
|
||||
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev See {EIP-5267}.
|
||||
*/
|
||||
function eip712Domain()
|
||||
public
|
||||
view
|
||||
virtual
|
||||
override
|
||||
returns (
|
||||
bytes1 fields,
|
||||
string memory name,
|
||||
string memory version,
|
||||
uint256 chainId,
|
||||
address verifyingContract,
|
||||
bytes32 salt,
|
||||
uint256[] memory extensions
|
||||
)
|
||||
{
|
||||
return (
|
||||
hex"0f", // 01111
|
||||
_name.toStringWithFallback(_nameFallback),
|
||||
_version.toStringWithFallback(_versionFallback),
|
||||
block.chainid,
|
||||
address(this),
|
||||
bytes32(0),
|
||||
new uint256[](0)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user