Commit a22f1634 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #6747 from ethereum-optimism/feat/eas-eip1271

feat: eas with eip1271 support
parents fa9a5476 50f8fda0
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
{ {
"src/EAS/EAS.sol": "0x00862a9f0088230acc1f5c5d0e4041bcc28cb3b3675d0eb7e1cceee7cf9502f8",
"src/EAS/SchemaRegistry.sol": "0xf1cd4415f85775124c226e1a356d8b9b5126b9e9bdbe5aebb3876d46f8e1217a",
"src/L1/L1CrossDomainMessenger.sol": "0x0e663b5d608b07cf278b94b1eeb3202abc01bea6b5905a3869010353df33ad1a", "src/L1/L1CrossDomainMessenger.sol": "0x0e663b5d608b07cf278b94b1eeb3202abc01bea6b5905a3869010353df33ad1a",
"src/L1/L1ERC721Bridge.sol": "0xbb10b777d1cd36ef98b53df6675f37a20b14a9a82b174f0d8f8872eedca65f17", "src/L1/L1ERC721Bridge.sol": "0xbb10b777d1cd36ef98b53df6675f37a20b14a9a82b174f0d8f8872eedca65f17",
"src/L1/L1StandardBridge.sol": "0xbd7b303cefe46bc14bf1a2b81e5702ff45ce9c5257524e59778e11c75f7f5bdc", "src/L1/L1StandardBridge.sol": "0xbd7b303cefe46bc14bf1a2b81e5702ff45ce9c5257524e59778e11c75f7f5bdc",
......
...@@ -13,8 +13,8 @@ error InvalidLength(); ...@@ -13,8 +13,8 @@ error InvalidLength();
error InvalidSignature(); error InvalidSignature();
error NotFound(); error NotFound();
/// @dev A struct representing EIP712 signature data. /// @dev A struct representing ECDSA signature data.
struct EIP712Signature { struct Signature {
uint8 v; // The recovery ID. uint8 v; // The recovery ID.
bytes32 r; // The x-coordinate of the nonce R. bytes32 r; // The x-coordinate of the nonce R.
bytes32 s; // The signature data. bytes32 s; // The signature data.
......
...@@ -4,13 +4,13 @@ pragma solidity 0.8.19; ...@@ -4,13 +4,13 @@ pragma solidity 0.8.19;
import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { Semver } from "../universal/Semver.sol"; import { Semver } from "../universal/Semver.sol";
import { Predeploys } from "../libraries/Predeploys.sol"; import { Predeploys } from "../libraries/Predeploys.sol";
import { EIP712Verifier } from "./eip712/EIP712Verifier.sol"; import { EIP1271Verifier } from "./eip1271/EIP1271Verifier.sol";
import { ISchemaResolver } from "./resolver/ISchemaResolver.sol"; import { ISchemaResolver } from "./resolver/ISchemaResolver.sol";
import { import {
AccessDenied, AccessDenied,
EMPTY_UID, EMPTY_UID,
EIP712Signature, Signature,
InvalidLength, InvalidLength,
MAX_GAP, MAX_GAP,
NotFound, NotFound,
...@@ -44,7 +44,7 @@ struct AttestationsResult { ...@@ -44,7 +44,7 @@ struct AttestationsResult {
/// @custom:predeploy 0x4200000000000000000000000000000000000021 /// @custom:predeploy 0x4200000000000000000000000000000000000021
/// @title EAS /// @title EAS
/// @notice The Ethereum Attestation Service protocol. /// @notice The Ethereum Attestation Service protocol.
contract EAS is IEAS, Semver, EIP712Verifier { contract EAS is IEAS, Semver, EIP1271Verifier {
using Address for address payable; using Address for address payable;
error AlreadyRevoked(); error AlreadyRevoked();
...@@ -80,7 +80,8 @@ contract EAS is IEAS, Semver, EIP712Verifier { ...@@ -80,7 +80,8 @@ contract EAS is IEAS, Semver, EIP712Verifier {
uint256[MAX_GAP - 3] private __gap; uint256[MAX_GAP - 3] private __gap;
/// @dev Creates a new EAS instance. /// @dev Creates a new EAS instance.
constructor() Semver(1, 0, 2) EIP712Verifier("EAS", "1.0.1") { } /// @custom:semver 1.1.0
constructor() Semver(1, 1, 0) EIP1271Verifier("EAS", "1.0.1") { }
/// @inheritdoc IEAS /// @inheritdoc IEAS
function getSchemaRegistry() external pure returns (ISchemaRegistry) { function getSchemaRegistry() external pure returns (ISchemaRegistry) {
...@@ -186,8 +187,7 @@ contract EAS is IEAS, Semver, EIP712Verifier { ...@@ -186,8 +187,7 @@ contract EAS is IEAS, Semver, EIP712Verifier {
revert InvalidLength(); revert InvalidLength();
} }
// Verify EIP712 signatures. Please note that the signatures are assumed to be signed with increasing // Verify signatures. Please note that the signatures are assumed to be signed with increasing nonces.
// nonces.
for (uint256 j = 0; j < data.length; j = uncheckedInc(j)) { for (uint256 j = 0; j < data.length; j = uncheckedInc(j)) {
_verifyAttest( _verifyAttest(
DelegatedAttestationRequest({ DelegatedAttestationRequest({
...@@ -287,8 +287,7 @@ contract EAS is IEAS, Semver, EIP712Verifier { ...@@ -287,8 +287,7 @@ contract EAS is IEAS, Semver, EIP712Verifier {
revert InvalidLength(); revert InvalidLength();
} }
// Verify EIP712 signatures. Please note that the signatures are assumed to be signed with increasing // Verify signatures. Please note that the signatures are assumed to be signed with increasing nonces.
// nonces.
for (uint256 j = 0; j < data.length; j = uncheckedInc(j)) { for (uint256 j = 0; j < data.length; j = uncheckedInc(j)) {
_verifyRevoke( _verifyRevoke(
DelegatedRevocationRequest({ DelegatedRevocationRequest({
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
import { ISchemaRegistry } from "./ISchemaRegistry.sol"; import { ISchemaRegistry } from "./ISchemaRegistry.sol";
import { Attestation, EIP712Signature } from "./Common.sol"; import { Attestation, Signature } from "./Common.sol";
/// @dev A struct representing the arguments of the attestation request. /// @dev A struct representing the arguments of the attestation request.
struct AttestationRequestData { struct AttestationRequestData {
...@@ -25,7 +25,7 @@ struct AttestationRequest { ...@@ -25,7 +25,7 @@ struct AttestationRequest {
struct DelegatedAttestationRequest { struct DelegatedAttestationRequest {
bytes32 schema; // The unique identifier of the schema. bytes32 schema; // The unique identifier of the schema.
AttestationRequestData data; // The arguments of the attestation request. AttestationRequestData data; // The arguments of the attestation request.
EIP712Signature signature; // The EIP712 signature data. Signature signature; // The ECDSA signature data.
address attester; // The attesting account. address attester; // The attesting account.
} }
...@@ -39,8 +39,8 @@ struct MultiAttestationRequest { ...@@ -39,8 +39,8 @@ struct MultiAttestationRequest {
struct MultiDelegatedAttestationRequest { struct MultiDelegatedAttestationRequest {
bytes32 schema; // The unique identifier of the schema. bytes32 schema; // The unique identifier of the schema.
AttestationRequestData[] data; // The arguments of the attestation requests. AttestationRequestData[] data; // The arguments of the attestation requests.
EIP712Signature[] signatures; // The EIP712 signatures data. Please note that the signatures are assumed to be Signature[] signatures; // The ECDSA signatures data. Please note that the signatures are assumed to be signed with
// signed with increasing nonces. // increasing nonces.
address attester; // The attesting account. address attester; // The attesting account.
} }
...@@ -61,7 +61,7 @@ struct RevocationRequest { ...@@ -61,7 +61,7 @@ struct RevocationRequest {
struct DelegatedRevocationRequest { struct DelegatedRevocationRequest {
bytes32 schema; // The unique identifier of the schema. bytes32 schema; // The unique identifier of the schema.
RevocationRequestData data; // The arguments of the revocation request. RevocationRequestData data; // The arguments of the revocation request.
EIP712Signature signature; // The EIP712 signature data. Signature signature; // The ECDSA signature data.
address revoker; // The revoking account. address revoker; // The revoking account.
} }
...@@ -75,8 +75,8 @@ struct MultiRevocationRequest { ...@@ -75,8 +75,8 @@ struct MultiRevocationRequest {
struct MultiDelegatedRevocationRequest { struct MultiDelegatedRevocationRequest {
bytes32 schema; // The unique identifier of the schema. bytes32 schema; // The unique identifier of the schema.
RevocationRequestData[] data; // The arguments of the revocation requests. RevocationRequestData[] data; // The arguments of the revocation requests.
EIP712Signature[] signatures; // The EIP712 signatures data. Please note that the signatures are assumed to be Signature[] signatures; // The ECDSA signatures data. Please note that the signatures are assumed to be signed with
// signed with increasing nonces. // increasing nonces.
address revoker; // The revoking account. address revoker; // The revoking account.
} }
......
...@@ -20,7 +20,8 @@ contract SchemaRegistry is ISchemaRegistry, Semver { ...@@ -20,7 +20,8 @@ contract SchemaRegistry is ISchemaRegistry, Semver {
uint256[MAX_GAP - 1] private __gap; uint256[MAX_GAP - 1] private __gap;
/// @dev Creates a new SchemaRegistry instance. /// @dev Creates a new SchemaRegistry instance.
constructor() Semver(1, 0, 2) { } /// @custom:semver 1.0.3
constructor() Semver(1, 0, 3) { }
/// @inheritdoc ISchemaRegistry /// @inheritdoc ISchemaRegistry
function register(string calldata schema, ISchemaResolver resolver, bool revocable) external returns (bytes32) { function register(string calldata schema, ISchemaResolver resolver, bool revocable) external returns (bytes32) {
......
...@@ -2,22 +2,23 @@ ...@@ -2,22 +2,23 @@
pragma solidity 0.8.19; pragma solidity 0.8.19;
import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { import {
AttestationRequest,
AttestationRequestData, AttestationRequestData,
DelegatedAttestationRequest, DelegatedAttestationRequest,
DelegatedRevocationRequest, DelegatedRevocationRequest,
RevocationRequest,
RevocationRequestData RevocationRequestData
} from "../IEAS.sol"; } from "../IEAS.sol";
import { EIP712Signature, InvalidSignature, MAX_GAP, stringToBytes32, bytes32ToString } from "../Common.sol"; import { Signature, InvalidSignature, MAX_GAP, stringToBytes32, bytes32ToString } from "../Common.sol";
/// @title EIP1271Verifier
/// @notice EIP1271Verifier typed signatures verifier for EAS delegated attestations.
abstract contract EIP1271Verifier is EIP712 {
using Address for address;
/// @title EIP712
/// @notice The EIP712 typed signatures verifier for EAS delegated attestations.
abstract contract EIP712Verifier is EIP712 {
// The hash of the data type used to relay calls to the attest function. It's the value of // The hash of the data type used to relay calls to the attest function. It's the value of
// keccak256("Attest(bytes32 schema,address recipient,uint64 expirationTime,bool revocable,bytes32 refUID,bytes // keccak256("Attest(bytes32 schema,address recipient,uint64 expirationTime,bool revocable,bytes32 refUID,bytes
// data,uint256 nonce)"). // data,uint256 nonce)").
...@@ -36,13 +37,14 @@ abstract contract EIP712Verifier is EIP712 { ...@@ -36,13 +37,14 @@ abstract contract EIP712Verifier is EIP712 {
// Upgrade forward-compatibility storage gap // Upgrade forward-compatibility storage gap
uint256[MAX_GAP - 1] private __gap; uint256[MAX_GAP - 1] private __gap;
/// @dev Creates a new EIP712Verifier instance. /// @dev Creates a new EIP1271Verifier instance.
/// @param version The current major version of the signing domain /// @param version The current major version of the signing domain
constructor(string memory name, string memory version) EIP712(name, version) { constructor(string memory name, string memory version) EIP712(name, version) {
_name = stringToBytes32(name); _name = stringToBytes32(name);
} }
/// @notice Returns the domain separator used in the encoding of the signatures for attest, and revoke. /// @notice Returns the domain separator used in the encoding of the signatures for attest, and revoke.
/// @return The domain separator used in the encoding of the signatures for attest, and revoke.
function getDomainSeparator() external view returns (bytes32) { function getDomainSeparator() external view returns (bytes32) {
return _domainSeparatorV4(); return _domainSeparatorV4();
} }
...@@ -55,13 +57,13 @@ abstract contract EIP712Verifier is EIP712 { ...@@ -55,13 +57,13 @@ abstract contract EIP712Verifier is EIP712 {
} }
/// @notice Returns the EIP712 type hash for the attest function. /// @notice Returns the EIP712 type hash for the attest function.
/// @return The EIP712 attest function type hash. /// @return The EIP712 type hash for the attest function.
function getAttestTypeHash() external pure returns (bytes32) { function getAttestTypeHash() external pure returns (bytes32) {
return ATTEST_TYPEHASH; return ATTEST_TYPEHASH;
} }
/// @notice Returns the EIP712 type hash for the revoke function. /// @notice Returns the EIP712 type hash for the revoke function.
/// @return hash_ The EIP712 revoke function type hash. /// @return The EIP712 type hash for the revoke function.
function getRevokeTypeHash() external pure returns (bytes32) { function getRevokeTypeHash() external pure returns (bytes32) {
return REVOKE_TYPEHASH; return REVOKE_TYPEHASH;
} }
...@@ -76,14 +78,14 @@ abstract contract EIP712Verifier is EIP712 { ...@@ -76,14 +78,14 @@ abstract contract EIP712Verifier is EIP712 {
/// @param request The arguments of the delegated attestation request. /// @param request The arguments of the delegated attestation request.
function _verifyAttest(DelegatedAttestationRequest memory request) internal { function _verifyAttest(DelegatedAttestationRequest memory request) internal {
AttestationRequestData memory data = request.data; AttestationRequestData memory data = request.data;
EIP712Signature memory signature = request.signature; Signature memory signature = request.signature;
uint256 nonce; uint256 nonce;
unchecked { unchecked {
nonce = _nonces[request.attester]++; nonce = _nonces[request.attester]++;
} }
bytes32 digest = _hashTypedDataV4( bytes32 hash = _hashTypedDataV4(
keccak256( keccak256(
abi.encode( abi.encode(
ATTEST_TYPEHASH, ATTEST_TYPEHASH,
...@@ -97,8 +99,11 @@ abstract contract EIP712Verifier is EIP712 { ...@@ -97,8 +99,11 @@ abstract contract EIP712Verifier is EIP712 {
) )
) )
); );
if (
if (ECDSA.recover(digest, signature.v, signature.r, signature.s) != request.attester) { !SignatureChecker.isValidSignatureNow(
request.attester, hash, abi.encodePacked(signature.r, signature.s, signature.v)
)
) {
revert InvalidSignature(); revert InvalidSignature();
} }
} }
...@@ -107,16 +112,19 @@ abstract contract EIP712Verifier is EIP712 { ...@@ -107,16 +112,19 @@ abstract contract EIP712Verifier is EIP712 {
/// @param request The arguments of the delegated revocation request. /// @param request The arguments of the delegated revocation request.
function _verifyRevoke(DelegatedRevocationRequest memory request) internal { function _verifyRevoke(DelegatedRevocationRequest memory request) internal {
RevocationRequestData memory data = request.data; RevocationRequestData memory data = request.data;
EIP712Signature memory signature = request.signature; Signature memory signature = request.signature;
uint256 nonce; uint256 nonce;
unchecked { unchecked {
nonce = _nonces[request.revoker]++; nonce = _nonces[request.revoker]++;
} }
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(REVOKE_TYPEHASH, request.schema, data.uid, nonce))); bytes32 hash = _hashTypedDataV4(keccak256(abi.encode(REVOKE_TYPEHASH, request.schema, data.uid, nonce)));
if (
if (ECDSA.recover(digest, signature.v, signature.r, signature.s) != request.revoker) { !SignatureChecker.isValidSignatureNow(
request.revoker, hash, abi.encodePacked(signature.r, signature.s, signature.v)
)
) {
revert InvalidSignature(); revert InvalidSignature();
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment