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/L1ERC721Bridge.sol": "0xbb10b777d1cd36ef98b53df6675f37a20b14a9a82b174f0d8f8872eedca65f17",
"src/L1/L1StandardBridge.sol": "0xbd7b303cefe46bc14bf1a2b81e5702ff45ce9c5257524e59778e11c75f7f5bdc",
......
......@@ -13,8 +13,8 @@ error InvalidLength();
error InvalidSignature();
error NotFound();
/// @dev A struct representing EIP712 signature data.
struct EIP712Signature {
/// @dev A struct representing ECDSA signature data.
struct Signature {
uint8 v; // The recovery ID.
bytes32 r; // The x-coordinate of the nonce R.
bytes32 s; // The signature data.
......
......@@ -4,13 +4,13 @@ pragma solidity 0.8.19;
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { Semver } from "../universal/Semver.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 {
AccessDenied,
EMPTY_UID,
EIP712Signature,
Signature,
InvalidLength,
MAX_GAP,
NotFound,
......@@ -44,7 +44,7 @@ struct AttestationsResult {
/// @custom:predeploy 0x4200000000000000000000000000000000000021
/// @title EAS
/// @notice The Ethereum Attestation Service protocol.
contract EAS is IEAS, Semver, EIP712Verifier {
contract EAS is IEAS, Semver, EIP1271Verifier {
using Address for address payable;
error AlreadyRevoked();
......@@ -80,7 +80,8 @@ contract EAS is IEAS, Semver, EIP712Verifier {
uint256[MAX_GAP - 3] private __gap;
/// @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
function getSchemaRegistry() external pure returns (ISchemaRegistry) {
......@@ -186,8 +187,7 @@ contract EAS is IEAS, Semver, EIP712Verifier {
revert InvalidLength();
}
// Verify EIP712 signatures. Please note that the signatures are assumed to be signed with increasing
// nonces.
// Verify signatures. Please note that the signatures are assumed to be signed with increasing nonces.
for (uint256 j = 0; j < data.length; j = uncheckedInc(j)) {
_verifyAttest(
DelegatedAttestationRequest({
......@@ -287,8 +287,7 @@ contract EAS is IEAS, Semver, EIP712Verifier {
revert InvalidLength();
}
// Verify EIP712 signatures. Please note that the signatures are assumed to be signed with increasing
// nonces.
// Verify signatures. Please note that the signatures are assumed to be signed with increasing nonces.
for (uint256 j = 0; j < data.length; j = uncheckedInc(j)) {
_verifyRevoke(
DelegatedRevocationRequest({
......
......@@ -2,7 +2,7 @@
pragma solidity ^0.8.0;
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.
struct AttestationRequestData {
......@@ -25,7 +25,7 @@ struct AttestationRequest {
struct DelegatedAttestationRequest {
bytes32 schema; // The unique identifier of the schema.
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.
}
......@@ -39,8 +39,8 @@ struct MultiAttestationRequest {
struct MultiDelegatedAttestationRequest {
bytes32 schema; // The unique identifier of the schema.
AttestationRequestData[] data; // The arguments of the attestation requests.
EIP712Signature[] signatures; // The EIP712 signatures data. Please note that the signatures are assumed to be
// signed with increasing nonces.
Signature[] signatures; // The ECDSA signatures data. Please note that the signatures are assumed to be signed with
// increasing nonces.
address attester; // The attesting account.
}
......@@ -61,7 +61,7 @@ struct RevocationRequest {
struct DelegatedRevocationRequest {
bytes32 schema; // The unique identifier of the schema.
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.
}
......@@ -75,8 +75,8 @@ struct MultiRevocationRequest {
struct MultiDelegatedRevocationRequest {
bytes32 schema; // The unique identifier of the schema.
RevocationRequestData[] data; // The arguments of the revocation requests.
EIP712Signature[] signatures; // The EIP712 signatures data. Please note that the signatures are assumed to be
// signed with increasing nonces.
Signature[] signatures; // The ECDSA signatures data. Please note that the signatures are assumed to be signed with
// increasing nonces.
address revoker; // The revoking account.
}
......
......@@ -20,7 +20,8 @@ contract SchemaRegistry is ISchemaRegistry, Semver {
uint256[MAX_GAP - 1] private __gap;
/// @dev Creates a new SchemaRegistry instance.
constructor() Semver(1, 0, 2) { }
/// @custom:semver 1.0.3
constructor() Semver(1, 0, 3) { }
/// @inheritdoc ISchemaRegistry
function register(string calldata schema, ISchemaResolver resolver, bool revocable) external returns (bytes32) {
......
......@@ -2,22 +2,23 @@
pragma solidity 0.8.19;
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 {
AttestationRequest,
AttestationRequestData,
DelegatedAttestationRequest,
DelegatedRevocationRequest,
RevocationRequest,
RevocationRequestData
} 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
// keccak256("Attest(bytes32 schema,address recipient,uint64 expirationTime,bool revocable,bytes32 refUID,bytes
// data,uint256 nonce)").
......@@ -36,13 +37,14 @@ abstract contract EIP712Verifier is EIP712 {
// Upgrade forward-compatibility storage 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
constructor(string memory name, string memory version) EIP712(name, version) {
_name = stringToBytes32(name);
}
/// @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) {
return _domainSeparatorV4();
}
......@@ -55,13 +57,13 @@ abstract contract EIP712Verifier is EIP712 {
}
/// @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) {
return ATTEST_TYPEHASH;
}
/// @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) {
return REVOKE_TYPEHASH;
}
......@@ -76,14 +78,14 @@ abstract contract EIP712Verifier is EIP712 {
/// @param request The arguments of the delegated attestation request.
function _verifyAttest(DelegatedAttestationRequest memory request) internal {
AttestationRequestData memory data = request.data;
EIP712Signature memory signature = request.signature;
Signature memory signature = request.signature;
uint256 nonce;
unchecked {
nonce = _nonces[request.attester]++;
}
bytes32 digest = _hashTypedDataV4(
bytes32 hash = _hashTypedDataV4(
keccak256(
abi.encode(
ATTEST_TYPEHASH,
......@@ -97,8 +99,11 @@ abstract contract EIP712Verifier is EIP712 {
)
)
);
if (ECDSA.recover(digest, signature.v, signature.r, signature.s) != request.attester) {
if (
!SignatureChecker.isValidSignatureNow(
request.attester, hash, abi.encodePacked(signature.r, signature.s, signature.v)
)
) {
revert InvalidSignature();
}
}
......@@ -107,16 +112,19 @@ abstract contract EIP712Verifier is EIP712 {
/// @param request The arguments of the delegated revocation request.
function _verifyRevoke(DelegatedRevocationRequest memory request) internal {
RevocationRequestData memory data = request.data;
EIP712Signature memory signature = request.signature;
Signature memory signature = request.signature;
uint256 nonce;
unchecked {
nonce = _nonces[request.revoker]++;
}
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(REVOKE_TYPEHASH, request.schema, data.uid, nonce)));
if (ECDSA.recover(digest, signature.v, signature.r, signature.s) != request.revoker) {
bytes32 hash = _hashTypedDataV4(keccak256(abi.encode(REVOKE_TYPEHASH, request.schema, data.uid, nonce)));
if (
!SignatureChecker.isValidSignatureNow(
request.revoker, hash, abi.encodePacked(signature.r, signature.s, signature.v)
)
) {
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