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

Allow Vote Changes to Reset Timelock and Approval State #135

Open
Henry-E opened this issue Nov 6, 2024 · 0 comments
Open

Allow Vote Changes to Reset Timelock and Approval State #135

Henry-E opened this issue Nov 6, 2024 · 0 comments

Comments

@Henry-E
Copy link

Henry-E commented Nov 6, 2024

Hey! Just noticed an interesting edge case with proposals in the Approved state that might be worth discussing.

Currently, once a proposal enters the Approved state (with its timelock countdown starting), there's no way to meaningfully change your vote if you were one of the approvers. While you can vote to cancel, this doesn't remove your original approval vote or reset the timelock countdown - it just adds your vote to a separate cancellation tally.

Here's a scenario where this gets tricky:
Let's say you have a timelock multisig where some keys get compromised. The attacker submits and approves a proposal, starting the 1-day timelock countdown. Even if you control one of the keys that voted to approve, changing that vote doesn't help much - you can't reset the timelock or move the proposal back to Active state. You'd need to reach a whole new threshold of cancel votes before the timelock expires.

Might be worth considering letting cancel votes remove approval votes (like reject votes do), or maybe resetting the timelock when approval votes change.

See:

/// Registers a cancellation vote.
pub fn cancel(&mut self, member: Pubkey, threshold: usize) -> Result<()> {
// Insert the vote of cancellation.
match self.cancelled.binary_search(&member) {
Ok(_) => return err!(MultisigError::AlreadyCancelled),
Err(pos) => self.cancelled.insert(pos, member),
};
// If current number of cancellations reaches threshold, mark the transaction as `Cancelled`.
if self.cancelled.len() >= threshold {
self.status = ProposalStatus::Cancelled {
timestamp: Clock::get()?.unix_timestamp,
};
}
Ok(())
}

vs.

pub fn reject(&mut self, member: Pubkey, cutoff: usize) -> Result<()> {
// If `member` has previously voted to approve, remove that vote.
if let Some(vote_index) = self.has_voted_approve(member.key()) {
self.remove_approval_vote(vote_index);
}
// Insert the vote of rejection.
match self.rejected.binary_search(&member) {
Ok(_) => return err!(MultisigError::AlreadyRejected),
Err(pos) => self.rejected.insert(pos, member),
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant