A single unfreeze dismisses all other slashing proposal freezes
In order to retaliate against malicious actors, the Forta staking system allows users to submit slashing proposals that are guarded by submitting along a deposit with a slashing reason. These proposals immediately freeze the proposal's subject's stake, blocking them from withdrawing that stake.\\nAt the same time, there can be multiple proposals submitted against the same subject, which works out with freezing - the subject remains frozen with each proposal submitted. However, once any one of the active proposals against the subject gets to the end of its lifecycle, be it `REJECTED`, `DISMISSED`, `EXECUTED`, or `REVERTED`, the subject gets unfrozen altogether. The other proposals might still be active, but the stake is no longer frozen, allowing the subject to withdraw it if they would like.\\nIn terms of impact, this allows bad actors to avoid punishment intended by the slashes and freezes. A malicious actor could, for example, submit a faulty proposal against themselves in the hopes that it will get quickly rejected or dismissed while the existing, legitimate proposals against them are still being considered. This would allow them to get unfrozen quickly and withdraw their stake. Similarly, in the event a bad staker has several proposals against them, they could withdraw right after a single slashing proposal goes through.\\n```\\nfunction dismissSlashProposal(uint256 \\_proposalId, string[] calldata \\_evidence) external onlyRole(SLASHING\\_ARBITER\\_ROLE) {\\n    \\_transition(\\_proposalId, DISMISSED);\\n    \\_submitEvidence(\\_proposalId, DISMISSED, \\_evidence);\\n    \\_returnDeposit(\\_proposalId);\\n    \\_unfreeze(\\_proposalId);\\n}\\n```\\n\\n```\\nfunction rejectSlashProposal(uint256 \\_proposalId, string[] calldata \\_evidence) external onlyRole(SLASHING\\_ARBITER\\_ROLE) {\\n    \\_transition(\\_proposalId, REJECTED);\\n    \\_submitEvidence(\\_proposalId, REJECTED, \\_evidence);\\n    \\_slashDeposit(\\_proposalId);\\n    \\_unfreeze(\\_proposalId);\\n}\\n```\\n\\n```\\nfunction reviewSlashProposalParameters(\\n    uint256 \\_proposalId,\\n    uint8 \\_subjectType,\\n    uint256 \\_subjectId,\\n    bytes32 \\_penaltyId,\\n    string[] calldata \\_evidence\\n) external onlyRole(SLASHING\\_ARBITER\\_ROLE) onlyInState(\\_proposalId, IN\\_REVIEW) onlyValidSlashPenaltyId(\\_penaltyId) onlyValidSubjectType(\\_subjectType) notAgencyType(\\_subjectType, SubjectStakeAgency.DELEGATOR) {\\n    // No need to check for proposal existence, onlyInState will revert if \\_proposalId is in undefined state\\n    if (!subjectGateway.isRegistered(\\_subjectType, \\_subjectId)) revert NonRegisteredSubject(\\_subjectType, \\_subjectId);\\n\\n    \\_submitEvidence(\\_proposalId, IN\\_REVIEW, \\_evidence);\\n    if (\\_subjectType != proposals[\\_proposalId].subjectType || \\_subjectId != proposals[\\_proposalId].subjectId) {\\n        \\_unfreeze(\\_proposalId);\\n        \\_freeze(\\_subjectType, \\_subjectId);\\n    }\\n```\\n\\n```\\nfunction revertSlashProposal(uint256 \\_proposalId, string[] calldata \\_evidence) external {\\n    \\_authorizeRevertSlashProposal(\\_proposalId);\\n    \\_transition(\\_proposalId, REVERTED);\\n    \\_submitEvidence(\\_proposalId, REVERTED, \\_evidence);\\n    \\_unfreeze(\\_proposalId);\\n}\\n```\\n\\n```\\nfunction executeSlashProposal(uint256 \\_proposalId) external onlyRole(SLASHER\\_ROLE) {\\n    \\_transition(\\_proposalId, EXECUTED);\\n    Proposal memory proposal = proposals[\\_proposalId];\\n    slashingExecutor.slash(proposal.subjectType, proposal.subjectId, getSlashedStakeValue(\\_proposalId), proposal.proposer, slashPercentToProposer);\\n    slashingExecutor.freeze(proposal.subjectType, proposal.subjectId, false);\\n}\\n```\\n\\n```\\nfunction \\_unfreeze(uint256 \\_proposalId) private {\\n    slashingExecutor.freeze(proposals[\\_proposalId].subjectType, proposals[\\_proposalId].subjectId, false);\\n}\\n```\\n
Introduce a check in the unfreezing mechanics to first ensure there are no other active proposals for that subject.
```\\nfunction dismissSlashProposal(uint256 \\_proposalId, string[] calldata \\_evidence) external onlyRole(SLASHING\\_ARBITER\\_ROLE) {\\n    \\_transition(\\_proposalId, DISMISSED);\\n    \\_submitEvidence(\\_proposalId, DISMISSED, \\_evidence);\\n    \\_returnDeposit(\\_proposalId);\\n    \\_unfreeze(\\_proposalId);\\n}\\n```\\n