-
Notifications
You must be signed in to change notification settings - Fork 121
/
SignedKeyRequestValidator.sol
138 lines (117 loc) · 5.24 KB
/
SignedKeyRequestValidator.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {Ownable2Step} from "openzeppelin/contracts/access/Ownable2Step.sol";
import {EIP712} from "openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {IMetadataValidator} from "../interfaces/IMetadataValidator.sol";
import {IdRegistryLike} from "../interfaces/IdRegistryLike.sol";
import {IdRegistry} from "../IdRegistry.sol";
contract SignedKeyRequestValidator is IMetadataValidator, Ownable2Step, EIP712 {
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Signed key request specific metadata.
*
* @param requestFid The fid of the entity requesting to add
* a signer key.
* @param requestSigner Signer address. Must be the owner of
* requestFid.
* @param signature EIP-712 SignedKeyRequest signature.
* @param deadline block.timestamp after which signature expires.
*/
struct SignedKeyRequestMetadata {
uint256 requestFid;
address requestSigner;
bytes signature;
uint256 deadline;
}
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @dev Emit an event when the admin sets a new IdRegistry contract address.
*
* @param oldIdRegistry The previous IdRegistry address.
* @param newIdRegistry The new IdRegistry address.
*/
event SetIdRegistry(address oldIdRegistry, address newIdRegistry);
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
bytes32 internal constant _METADATA_TYPEHASH =
keccak256("SignedKeyRequest(uint256 requestFid,bytes key,uint256 deadline)");
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/**
* @dev The IdRegistry contract.
*/
IdRegistryLike public idRegistry;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/**
* @notice Set the IdRegistry and owner.
*
* @param _idRegistry IdRegistry contract address.
* @param _initialOwner Initial contract owner address.
*/
constructor(address _idRegistry, address _initialOwner) EIP712("Farcaster SignedKeyRequestValidator", "1") {
idRegistry = IdRegistryLike(_idRegistry);
_transferOwnership(_initialOwner);
}
/*//////////////////////////////////////////////////////////////
VALIDATION
//////////////////////////////////////////////////////////////*/
/**
* @notice Validate the SignedKeyRequest metadata associated with a signer key.
* (Key type 1, Metadata type 1)
*
* @param key The EdDSA public key of the signer.
* @param signedKeyRequestBytes An abi-encoded SignedKeyRequest struct, provided as the
* metadata argument to KeyRegistry.add.
*
* @return true if signature is valid and signer owns requestFid, false otherwise.
*/
function validate(
uint256, /* userFid */
bytes memory key,
bytes calldata signedKeyRequestBytes
) external view returns (bool) {
SignedKeyRequestMetadata memory metadata = abi.decode(signedKeyRequestBytes, (SignedKeyRequestMetadata));
if (idRegistry.idOf(metadata.requestSigner) != metadata.requestFid) {
return false;
}
if (block.timestamp > metadata.deadline) return false;
if (key.length != 32) return false;
return idRegistry.verifyFidSignature(
metadata.requestSigner,
metadata.requestFid,
_hashTypedDataV4(
keccak256(abi.encode(_METADATA_TYPEHASH, metadata.requestFid, keccak256(key), metadata.deadline))
),
metadata.signature
);
}
/*//////////////////////////////////////////////////////////////
HELPERS
//////////////////////////////////////////////////////////////*/
function hashTypedDataV4(bytes32 structHash) external view returns (bytes32) {
return _hashTypedDataV4(structHash);
}
function encodeMetadata(SignedKeyRequestMetadata calldata metadata) external pure returns (bytes memory) {
return abi.encode(metadata);
}
/*//////////////////////////////////////////////////////////////
ADMIN
//////////////////////////////////////////////////////////////*/
/**
* @notice Set the IdRegistry contract address. Only callable by owner.
*
* @param _idRegistry The new IdRegistry address.
*/
function setIdRegistry(address _idRegistry) external onlyOwner {
emit SetIdRegistry(address(idRegistry), _idRegistry);
idRegistry = IdRegistryLike(_idRegistry);
}
}