-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add eip712 authenticator (#20)
* chore: install bytes lib * forge install: solidity-bytes-utils v0.8.0 * chore: removed solidity bytes utils * feat: propose sig verification * feat: Signature utils contract for tests * refactor: formatting * fix: proper eip712 encoding for Propose Sigs * refactor: moved function signature to abstract base contract * fix: decoding propose data for sig verification * refactor: moved typed data hashing functions to SigUtils * test: updated eth sig auth tests * fix: cleaned up remappings.txt * chore: cleared submodule cache * feat: dedicated type hashing lib * feat: store salt to prevent replay attacks * test: propose signature revert cases * style: formatting * refactor: moved Signature Verifier to utils * feat: eip712 authentication for vote * feat: tests for eip712 vote * fix: removed redundant 0 check on sig verifier Co-authored-by: Deep Work Station <[email protected]> Co-authored-by: Orlando <[email protected]>
- Loading branch information
1 parent
ef22a88
commit 8971527
Showing
12 changed files
with
576 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule solidity-bytes-utils
deleted from
6458fb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.15; | ||
|
||
import "./Authenticator.sol"; | ||
import "../utils/SignatureVerifier.sol"; | ||
|
||
contract EthSigAuthenticator is Authenticator, SignatureVerifier { | ||
error InvalidFunctionSelector(); | ||
|
||
constructor(string memory name, string memory version) SignatureVerifier(name, version) {} | ||
|
||
function authenticate( | ||
uint8 v, | ||
bytes32 r, | ||
bytes32 s, | ||
uint256 salt, | ||
address target, | ||
bytes4 functionSelector, | ||
bytes calldata data | ||
) external { | ||
if (functionSelector == PROPOSE_SELECTOR) { | ||
_verifyProposeSig(v, r, s, salt, target, data); | ||
} else if (functionSelector == VOTE_SELECTOR) { | ||
_verifyVoteSig(v, r, s, salt, target, data); | ||
} else { | ||
revert InvalidFunctionSelector(); | ||
} | ||
_call(target, functionSelector, data); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.15; | ||
|
||
import "src/types.sol"; | ||
|
||
/// @title SOC Types Hashing Library | ||
/// @notice This library contains functions for hashing SOC types for use in eip712 signatures. | ||
/// TODO: rename once we have a better name for SOC | ||
library SOCHash { | ||
bytes32 private constant STRATEGY_TYPEHASH = keccak256("Strategy(address addy,bytes params)"); | ||
bytes32 private constant INDEXED_STRATEGY_TYPEHASH = keccak256("IndexedStrategy(uint8 index,bytes params)"); | ||
bytes32 private constant PROPOSE_TYPEHASH = | ||
keccak256( | ||
"Propose(address space,address author,string metadataUri,Strategy executionStrategy," | ||
"IndexedStrategy[] userVotingStrategies,uint256 salt)" | ||
); | ||
|
||
function hash(Strategy memory strategy) internal pure returns (bytes32) { | ||
return keccak256(abi.encode(STRATEGY_TYPEHASH, strategy)); | ||
} | ||
|
||
function hash(IndexedStrategy[] memory indexedStrategies) internal pure returns (bytes32) { | ||
bytes32[] memory indexedStrategyHashes = new bytes32[](indexedStrategies.length); | ||
for (uint256 i = 0; i < indexedStrategies.length; i++) { | ||
indexedStrategyHashes[i] = keccak256(abi.encode(INDEXED_STRATEGY_TYPEHASH, indexedStrategies[i])); | ||
} | ||
return keccak256(abi.encodePacked(indexedStrategyHashes)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.15; | ||
|
||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | ||
import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; | ||
import "src/types.sol"; | ||
import { SOCHash } from "src/utils/SOCHash.sol"; | ||
|
||
abstract contract SignatureVerifier is EIP712 { | ||
using SOCHash for Strategy; | ||
using SOCHash for IndexedStrategy[]; | ||
|
||
error InvalidSignature(); | ||
error SaltAlreadyUsed(); | ||
|
||
bytes32 private constant PROPOSE_TYPEHASH = | ||
keccak256( | ||
"Propose(address space,address author,string metadataUri,Strategy executionStrategy," | ||
"IndexedStrategy[] userVotingStrategies,uint256 salt)" | ||
); | ||
bytes32 private constant VOTE_TYPEHASH = | ||
keccak256( | ||
"Vote(address space,address voter,uint256 proposalId,Choice choice," | ||
"IndexedStrategy[] userVotingStrategies,uint256 salt)" | ||
); | ||
|
||
mapping(address => mapping(uint256 => bool)) private usedSalts; | ||
|
||
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, | ||
Strategy memory executionStrategy, | ||
IndexedStrategy[] memory userVotingStrategies | ||
) = abi.decode(data, (address, string, Strategy, 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, uint256 salt, address space, bytes memory data) internal { | ||
(address voter, uint256 proposeId, Choice choice, IndexedStrategy[] memory userVotingStrategies) = abi.decode( | ||
data, | ||
(address, uint256, Choice, IndexedStrategy[]) | ||
); | ||
|
||
if (usedSalts[voter][salt]) revert SaltAlreadyUsed(); | ||
|
||
address recoveredAddress = ECDSA.recover( | ||
_hashTypedDataV4( | ||
keccak256(abi.encode(VOTE_TYPEHASH, space, voter, proposeId, choice, userVotingStrategies.hash(), salt)) | ||
), | ||
v, | ||
r, | ||
s | ||
); | ||
|
||
if (recoveredAddress != voter) revert InvalidSignature(); | ||
|
||
// Mark salt as used to prevent replay attacks | ||
usedSalts[voter][salt] = true; | ||
} | ||
} |
Oops, something went wrong.