fix: fix: Conditional lock on feeDestination — lock when set to contract (#580) (#580)

- Add `feeDestinationLocked` bool to LiquidityManager
- Replace one-shot setter with conditional trapdoor: EOAs may be set
  repeatedly, but setting a contract address locks permanently
- Remove `AddressAlreadySet` error (superseded by the new lock mechanic)
- Replace fragile SLOT7 storage hack in red-team.sh with a proper
  `setFeeDestination()` call using the deployer key
- Update tests: replace AddressAlreadySet test with three new tests
  covering EOA multi-set, contract lock, and locked revert

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-12 16:13:44 +00:00
parent fff0ca60e7
commit 512640226b
3 changed files with 39 additions and 19 deletions

View file

@ -1017,14 +1017,35 @@ contract LiquidityManagerTest is UniSwapHelper {
}
/**
* @notice AddressAlreadySet revert when fee destination is changed after initial set
* @notice EOA destinations can be set repeatedly no lock until a contract is set
*/
function testSetFeeDestinationAlreadySet() public {
// Deploy a fresh LM with this test contract as deployer
function testSetFeeDestinationEOA_MultipleAllowed() public {
LiquidityManager freshLm = new LiquidityManager(address(factory), address(weth), address(harberg), address(optimizer));
freshLm.setFeeDestination(makeAddr("firstFee"));
vm.expectRevert(LiquidityManager.AddressAlreadySet.selector);
assertFalse(freshLm.feeDestinationLocked(), "should not be locked after EOA set");
freshLm.setFeeDestination(makeAddr("secondFee"));
assertFalse(freshLm.feeDestinationLocked(), "should still not be locked after second EOA set");
}
/**
* @notice Setting fee destination to a contract locks it permanently
*/
function testSetFeeDestinationContract_Locks() public {
LiquidityManager freshLm = new LiquidityManager(address(factory), address(weth), address(harberg), address(optimizer));
// address(harberg) is a deployed contract
freshLm.setFeeDestination(address(harberg));
assertTrue(freshLm.feeDestinationLocked(), "should be locked after contract set");
assertEq(freshLm.feeDestination(), address(harberg));
}
/**
* @notice Once locked, setFeeDestination reverts
*/
function testSetFeeDestinationLocked_Reverts() public {
LiquidityManager freshLm = new LiquidityManager(address(factory), address(weth), address(harberg), address(optimizer));
freshLm.setFeeDestination(address(harberg));
vm.expectRevert("fee destination locked");
freshLm.setFeeDestination(makeAddr("anyAddr"));
}
/**