github.com/ethereum-optimism/optimism@v1.7.2/packages/contracts-bedrock/src/EAS/eip1271/EIP1271Verifier.sol (about) 1 // SPDX-License-Identifier: MIT 2 pragma solidity 0.8.19; 3 4 import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; 5 import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; 6 import { Address } from "@openzeppelin/contracts/utils/Address.sol"; 7 8 import { 9 AttestationRequestData, 10 DelegatedAttestationRequest, 11 DelegatedRevocationRequest, 12 RevocationRequestData 13 } from "src/EAS/IEAS.sol"; 14 15 import { 16 DeadlineExpired, 17 NO_EXPIRATION_TIME, 18 Signature, 19 InvalidSignature, 20 MAX_GAP, 21 stringToBytes32, 22 bytes32ToString 23 } from "src/EAS/Common.sol"; 24 25 /// @title EIP1271Verifier 26 /// @notice EIP1271Verifier typed signatures verifier for EAS delegated attestations. 27 abstract contract EIP1271Verifier is EIP712 { 28 using Address for address; 29 30 error InvalidNonce(); 31 32 // The hash of the data type used to relay calls to the attest function. It's the value of 33 // keccak256("Attest(address attester,bytes32 schema,address recipient,uint64 expirationTime,bool revocable,bytes32 34 // refUID,bytes data,uint256 value,uint256 nonce,uint64 deadline)"). 35 bytes32 private constant ATTEST_TYPEHASH = 0xfeb2925a02bae3dae48d424a0437a2b6ac939aa9230ddc55a1a76f065d988076; 36 37 // The hash of the data type used to relay calls to the revoke function. It's the value of 38 // keccak256("Revoke(address revoker,bytes32 schema,bytes32 uid,uint256 value,uint256 nonce,uint64 deadline)"). 39 bytes32 private constant REVOKE_TYPEHASH = 0xb5d556f07587ec0f08cf386545cc4362c702a001650c2058002615ee5c9d1e75; 40 41 // The user readable name of the signing domain. 42 bytes32 private immutable _name; 43 44 // Replay protection nonces. 45 mapping(address => uint256) private _nonces; 46 47 // Upgrade forward-compatibility storage gap 48 uint256[MAX_GAP - 1] private __gap; 49 50 /// @dev Emitted when users invalidate nonces by increasing their nonces to (higher) new values. 51 /// @param oldNonce The previous nonce. 52 /// @param newNonce The new value. 53 event NonceIncreased(uint256 oldNonce, uint256 newNonce); 54 55 /// @dev Creates a new EIP1271Verifier instance. 56 /// @param version The current major version of the signing domain 57 constructor(string memory name, string memory version) EIP712(name, version) { 58 _name = stringToBytes32(name); 59 } 60 61 /// @notice Returns the domain separator used in the encoding of the signatures for attest, and revoke. 62 /// @return The domain separator used in the encoding of the signatures for attest, and revoke. 63 function getDomainSeparator() external view returns (bytes32) { 64 return _domainSeparatorV4(); 65 } 66 67 /// @notice Returns the current nonce per-account. 68 /// @param account The requested account. 69 /// @return The current nonce. 70 function getNonce(address account) external view returns (uint256) { 71 return _nonces[account]; 72 } 73 74 /// @notice Returns the EIP712 type hash for the attest function. 75 /// @return The EIP712 type hash for the attest function. 76 function getAttestTypeHash() external pure returns (bytes32) { 77 return ATTEST_TYPEHASH; 78 } 79 80 /// @notice Returns the EIP712 type hash for the revoke function. 81 /// @return The EIP712 type hash for the revoke function. 82 function getRevokeTypeHash() external pure returns (bytes32) { 83 return REVOKE_TYPEHASH; 84 } 85 86 /// @notice Returns the EIP712 name. 87 /// @return The EIP712 name. 88 function getName() external view returns (string memory) { 89 return bytes32ToString(_name); 90 } 91 92 /// @notice Provides users an option to invalidate nonces by increasing their nonces to (higher) new values. 93 /// @param newNonce The (higher) new value. 94 function increaseNonce(uint256 newNonce) external { 95 uint256 oldNonce = _nonces[msg.sender]; 96 if (newNonce <= oldNonce) { 97 revert InvalidNonce(); 98 } 99 100 _nonces[msg.sender] = newNonce; 101 102 emit NonceIncreased({ oldNonce: oldNonce, newNonce: newNonce }); 103 } 104 105 /// @notice Verifies delegated attestation request. 106 /// @param request The arguments of the delegated attestation request. 107 function _verifyAttest(DelegatedAttestationRequest memory request) internal { 108 if (request.deadline != NO_EXPIRATION_TIME && request.deadline < _time()) { 109 revert DeadlineExpired(); 110 } 111 112 AttestationRequestData memory data = request.data; 113 Signature memory signature = request.signature; 114 115 bytes32 hash = _hashTypedDataV4( 116 keccak256( 117 abi.encode( 118 ATTEST_TYPEHASH, 119 request.attester, 120 request.schema, 121 data.recipient, 122 data.expirationTime, 123 data.revocable, 124 data.refUID, 125 keccak256(data.data), 126 data.value, 127 _nonces[request.attester]++, 128 request.deadline 129 ) 130 ) 131 ); 132 if ( 133 !SignatureChecker.isValidSignatureNow( 134 request.attester, hash, abi.encodePacked(signature.r, signature.s, signature.v) 135 ) 136 ) { 137 revert InvalidSignature(); 138 } 139 } 140 141 /// @notice Verifies delegated revocation request. 142 /// @param request The arguments of the delegated revocation request. 143 function _verifyRevoke(DelegatedRevocationRequest memory request) internal { 144 if (request.deadline != NO_EXPIRATION_TIME && request.deadline < _time()) { 145 revert DeadlineExpired(); 146 } 147 148 RevocationRequestData memory data = request.data; 149 Signature memory signature = request.signature; 150 151 bytes32 hash = _hashTypedDataV4( 152 keccak256( 153 abi.encode( 154 REVOKE_TYPEHASH, 155 request.revoker, 156 request.schema, 157 data.uid, 158 data.value, 159 _nonces[request.revoker]++, 160 request.deadline 161 ) 162 ) 163 ); 164 if ( 165 !SignatureChecker.isValidSignatureNow( 166 request.revoker, hash, abi.encodePacked(signature.r, signature.s, signature.v) 167 ) 168 ) { 169 revert InvalidSignature(); 170 } 171 } 172 173 /// @dev Returns the current's block timestamp. This method is overridden during tests and used to simulate the 174 /// current block time. 175 function _time() internal view virtual returns (uint64) { 176 return uint64(block.timestamp); 177 } 178 }