Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

addContender by signature only #232

Merged
merged 15 commits into from
Dec 28, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ contract SecurityCouncilNomineeElectionGovernor is
error QuorumNumeratorTooLow(uint256 quorumNumeratorValue);
error CastVoteDisabled();
error LastMemberElectionNotExecuted(uint256 prevProposalId);
error InvalidSignature();

constructor() {
_disableInitializers();
Expand Down Expand Up @@ -215,11 +216,16 @@ contract SecurityCouncilNomineeElectionGovernor is
/// during the vetting phase and exclude any contenders which dont meet this criteria.
/// @dev Can be called only while a proposal is pending (after proposal created but before voting phase)
/// A contender cannot be a member of the opposite cohort.
function addContender(uint256 proposalId) external {
DZGoldman marked this conversation as resolved.
Show resolved Hide resolved
function addContender(uint256 proposalId, bytes calldata signature) external {
address signer = recoverAddContenderMessage(proposalId, signature);
if (signer == address(0)) {
revert InvalidSignature();
}

ElectionInfo storage election = _elections[proposalId];

if (election.isContender[msg.sender]) {
revert AlreadyContender(msg.sender);
if (election.isContender[signer]) {
revert AlreadyContender(signer);
}

ProposalState state_ = state(proposalId);
Expand All @@ -233,13 +239,13 @@ contract SecurityCouncilNomineeElectionGovernor is
// this check then is only a relevant check when the elections are running as expected - one at a time,
// every 6 months. Updates to the sec council manager using methods other than replaceCohort can effect this check
// and it's expected that the entity making those updates understands this.
if (securityCouncilManager.cohortIncludes(otherCohort(), msg.sender)) {
revert AccountInOtherCohort(otherCohort(), msg.sender);
if (securityCouncilManager.cohortIncludes(otherCohort(), signer)) {
revert AccountInOtherCohort(otherCohort(), signer);
}

election.isContender[msg.sender] = true;
election.isContender[signer] = true;

emit ContenderAdded(proposalId, msg.sender);
emit ContenderAdded(proposalId, signer);
}

/// @notice Allows the owner to change the nomineeVetter
Expand Down Expand Up @@ -423,6 +429,15 @@ contract SecurityCouncilNomineeElectionGovernor is
return _elections[proposalId].isContender[possibleContender];
}

/// @notice Recover EIP712 signature for `AddContenderMessage`
function recoverAddContenderMessage(uint256 proposalId, bytes calldata signature) public view returns (address) {
bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
keccak256("AddContenderMessage(uint256 proposalId)"),
proposalId
)));
return ECDSAUpgradeable.recover(digest, signature);
}

/// @notice Always reverts.
/// @dev `GovernorUpgradeable` function to create a proposal overridden to just revert.
/// We only want proposals to be created via `createElection`.
Expand Down
Loading