-
Notifications
You must be signed in to change notification settings - Fork 10
/
SignatureVerifier.sol
131 lines (113 loc) · 4.56 KB
/
SignatureVerifier.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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import { Choice, IndexedStrategy } from "src/types.sol";
import { SXHash } from "src/utils/SXHash.sol";
abstract contract SignatureVerifier is EIP712 {
using SXHash for IndexedStrategy[];
using SXHash for IndexedStrategy;
error InvalidSignature();
error SaltAlreadyUsed();
bytes32 private constant PROPOSE_TYPEHASH =
keccak256(
"Propose(address space,address author,string metadataUri,IndexedStrategy executionStrategy,"
"IndexedStrategy[] userVotingStrategies,uint256 salt)"
"IndexedStrategy(uint8 index,bytes params)"
);
bytes32 private constant VOTE_TYPEHASH =
keccak256(
"Vote(address space,address voter,uint256 proposalId,uint8 choice,"
"IndexedStrategy[] userVotingStrategies,string voteMetadataUri)"
"IndexedStrategy(uint8 index,bytes params)"
);
bytes32 private constant UPDATE_PROPOSAL_TYPEHASH =
keccak256(
"updateProposal(address space,address author,uint256 proposalId,"
"IndexedStrategy executionStrategy,string metadataUri)"
"IndexedStrategy(uint8 index,bytes params)"
);
mapping(address author => mapping(uint256 salt => bool used)) private usedSalts;
// solhint-disable-next-line no-empty-blocks
constructor(string memory name, string memory version) EIP712(name, version) {}
function _verifyProposeSig(uint8 v, bytes32 r, bytes32 s, uint256 salt, address space, bytes memory data) internal {
(
address author,
string memory metadataUri,
IndexedStrategy memory executionStrategy,
IndexedStrategy[] memory userVotingStrategies
) = abi.decode(data, (address, string, IndexedStrategy, IndexedStrategy[]));
if (usedSalts[author][salt]) revert SaltAlreadyUsed();
address recoveredAddress = ECDSA.recover(
_hashTypedDataV4(
keccak256(
abi.encode(
PROPOSE_TYPEHASH,
space,
author,
keccak256(bytes(metadataUri)),
executionStrategy.hash(),
userVotingStrategies.hash(),
salt
)
)
),
v,
r,
s
);
if (recoveredAddress != author) revert InvalidSignature();
// Mark salt as used to prevent replay attacks
usedSalts[author][salt] = true;
}
function _verifyVoteSig(uint8 v, bytes32 r, bytes32 s, address space, bytes memory data) internal view {
(
address voter,
uint256 proposeId,
Choice choice,
IndexedStrategy[] memory userVotingStrategies,
string memory voteMetadataUri
) = abi.decode(data, (address, uint256, Choice, IndexedStrategy[], string));
address recoveredAddress = ECDSA.recover(
_hashTypedDataV4(
keccak256(
abi.encode(
VOTE_TYPEHASH,
space,
voter,
proposeId,
choice,
userVotingStrategies.hash(),
keccak256(bytes(voteMetadataUri))
)
)
),
v,
r,
s
);
if (recoveredAddress != voter) revert InvalidSignature();
}
function _verifyUpdateProposalSig(uint8 v, bytes32 r, bytes32 s, address space, bytes memory data) internal view {
(address author, uint256 proposalId, IndexedStrategy memory executionStrategy, string memory metadataUri) = abi
.decode(data, (address, uint256, IndexedStrategy, string));
address recoveredAddress = ECDSA.recover(
_hashTypedDataV4(
keccak256(
abi.encode(
UPDATE_PROPOSAL_TYPEHASH,
space,
author,
proposalId,
executionStrategy.hash(),
keccak256(bytes(metadataUri))
)
)
),
v,
r,
s
);
if (recoveredAddress != author) revert InvalidSignature();
}
}