draft-EIP712Upgradeable.sol 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)
  3. pragma solidity ^0.8.0;
  4. import "./ECDSAUpgradeable.sol";
  5. import "../../proxy/utils/Initializable.sol";
  6. /**
  7. * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
  8. *
  9. * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
  10. * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
  11. * they need in their contracts using a combination of `abi.encode` and `keccak256`.
  12. *
  13. * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
  14. * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
  15. * ({_hashTypedDataV4}).
  16. *
  17. * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
  18. * the chain id to protect against replay attacks on an eventual fork of the chain.
  19. *
  20. * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
  21. * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
  22. *
  23. * _Available since v3.4._
  24. */
  25. abstract contract EIP712Upgradeable is Initializable {
  26. /* solhint-disable var-name-mixedcase */
  27. bytes32 private _HASHED_NAME;
  28. bytes32 private _HASHED_VERSION;
  29. bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
  30. /* solhint-enable var-name-mixedcase */
  31. /**
  32. * @dev Initializes the domain separator and parameter caches.
  33. *
  34. * The meaning of `name` and `version` is specified in
  35. * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
  36. *
  37. * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
  38. * - `version`: the current major version of the signing domain.
  39. *
  40. * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
  41. * contract upgrade].
  42. */
  43. function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
  44. __EIP712_init_unchained(name, version);
  45. }
  46. function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
  47. bytes32 hashedName = keccak256(bytes(name));
  48. bytes32 hashedVersion = keccak256(bytes(version));
  49. _HASHED_NAME = hashedName;
  50. _HASHED_VERSION = hashedVersion;
  51. }
  52. /**
  53. * @dev Returns the domain separator for the current chain.
  54. */
  55. function _domainSeparatorV4() internal view returns (bytes32) {
  56. return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash());
  57. }
  58. function _buildDomainSeparator(
  59. bytes32 typeHash,
  60. bytes32 nameHash,
  61. bytes32 versionHash
  62. ) private view returns (bytes32) {
  63. return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
  64. }
  65. /**
  66. * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
  67. * function returns the hash of the fully encoded EIP712 message for this domain.
  68. *
  69. * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
  70. *
  71. * ```solidity
  72. * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
  73. * keccak256("Mail(address to,string contents)"),
  74. * mailTo,
  75. * keccak256(bytes(mailContents))
  76. * )));
  77. * address signer = ECDSA.recover(digest, signature);
  78. * ```
  79. */
  80. function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
  81. return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash);
  82. }
  83. /**
  84. * @dev The hash of the name parameter for the EIP712 domain.
  85. *
  86. * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
  87. * are a concern.
  88. */
  89. function _EIP712NameHash() internal virtual view returns (bytes32) {
  90. return _HASHED_NAME;
  91. }
  92. /**
  93. * @dev The hash of the version parameter for the EIP712 domain.
  94. *
  95. * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
  96. * are a concern.
  97. */
  98. function _EIP712VersionHash() internal virtual view returns (bytes32) {
  99. return _HASHED_VERSION;
  100. }
  101. /**
  102. * This empty reserved space is put in place to allow future versions to add new
  103. * variables without shifting down storage in the inheritance chain.
  104. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
  105. */
  106. uint256[50] private __gap;
  107. }