pool = _deployPool(blacklistToken);
_stakeBlacklist(alice, 100 * ONE);
blacklistToken.setBlacklist(recovery, true);
vm.expectRevert("Blacklisted");
pool.claimCorrupted();
function test_M2_BlacklistedRecoveryAddress_BricksClaimCorrupted() public {
pool = _deployPool(address(blacklistToken));
_stakeBlacklist(alice, 100 * ONE, blacklistToken);
_passThroughUnderAttack();
attackRegistry.setAgreementState(IAttackRegistry.ContractState.CORRUPTED);
vm.prank(moderator);
pool.flagOutcome(PoolStates.Outcome.CORRUPTED, false, address(0));
blacklistToken.setBlacklist(recovery, true);
vm.expectRevert("Blacklisted");
pool.claimCorrupted();
}
function test_M2_BlacklistedAttacker_BricksGoodFaithBounty() public {
pool = _deployPool(address(blacklistToken));
_stakeBlacklist(alice, 100 * ONE, blacklistToken);
_passThroughUnderAttack();
attackRegistry.setAgreementState(IAttackRegistry.ContractState.CORRUPTED);
vm.prank(moderator);
pool.flagOutcome(PoolStates.Outcome.CORRUPTED, true, attacker);
blacklistToken.setBlacklist(attacker, true);
vm.expectRevert("Blacklisted");
vm.prank(attacker);
pool.claimAttackerBounty();
vm.expectRevert(IConfidencePool.MustClaimBountyFirst.selector);
pool.claimCorrupted();
}
function test_M2_BlacklistedStaker_BricksIndividualClaim() public {
pool = _deployPool(address(blacklistToken));
_stakeBlacklist(alice, 100 * ONE, blacklistToken);
_stakeBlacklist(bob, 50 * ONE, blacklistToken);
_contributeBonusBlacklist(carol, 30 * ONE, blacklistToken);
attackRegistry.setAgreementState(IAttackRegistry.ContractState.PRODUCTION);
vm.prank(moderator);
pool.flagOutcome(PoolStates.Outcome.SURVIVED, false, address(0));
blacklistToken.setBlacklist(alice, true);
vm.expectRevert("Blacklisted");
vm.prank(alice);
pool.claimSurvived();
vm.prank(bob);
pool.claimSurvived();
}
+ // Add pull-payment pattern for critical addresses
+ mapping(address => uint256) public pendingWithdrawals;
+
+ function claimCorrupted() external nonReentrant {
+ // ... validation ...
+ pendingWithdrawals[recoveryAddress] += amount;
+ emit CorruptedClaimed(recoveryAddress, amount);
+ }
+
+ function withdrawPending() external {
+ uint256 amount = pendingWithdrawals[msg.sender];
+ require(amount > 0, "Nothing to withdraw");
+ pendingWithdrawals[msg.sender] = 0;
+ stakeToken.safeTransfer(msg.sender, amount);
+ }
+
// Also add address update capability for recovery/attacker
function setRecoveryAddress(address newRecovery) external onlyOwner {
recoveryAddress = newRecovery;
}