fix: address review findings — CREATE2 guard, transition test, docs

- LiquidityManager.setFeeDestination: add CREATE2 bypass guard — also
  blocks re-assignment when the current feeDestination has since acquired
  bytecode (was a plain address when set, contract deployed to it later)
- LiquidityManager.setFeeDestination: expand NatSpec to document the
  EOA-mutability trade-off and the CREATE2 guard explicitly
- Test: add testSetFeeDestinationEOAToContract_Locks covering the
  realistic EOA→contract transition (the primary lock-activation path)
- red-team.sh: add comment that DEPLOYER_PK is Anvil account-0 and must
  only be used against a local ephemeral Anvil instance
- ARCHITECTURE.md: document feeDestination conditional-lock semantics and
  contrast with Kraiken's strictly set-once liquidityManager/stakingPool

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-12 17:13:50 +00:00
parent 9ff96ff137
commit b902b89e3b
4 changed files with 35 additions and 4 deletions

View file

@ -1028,7 +1028,7 @@ contract LiquidityManagerTest is UniSwapHelper {
}
/**
* @notice Setting fee destination to a contract locks it permanently
* @notice Setting fee destination to a contract locks it permanently (direct path)
*/
function testSetFeeDestinationContract_Locks() public {
LiquidityManager freshLm = new LiquidityManager(address(factory), address(weth), address(harberg), address(optimizer));
@ -1038,6 +1038,23 @@ contract LiquidityManagerTest is UniSwapHelper {
assertEq(freshLm.feeDestination(), address(harberg));
}
/**
* @notice Realistic deployment path: set EOA first, then upgrade to a contract lock triggers on transition
*/
function testSetFeeDestinationEOAToContract_Locks() public {
LiquidityManager freshLm = new LiquidityManager(address(factory), address(weth), address(harberg), address(optimizer));
// Step 1: set to an EOA during setup allowed, not locked
freshLm.setFeeDestination(makeAddr("treasuryEOA"));
assertFalse(freshLm.feeDestinationLocked(), "not locked after EOA set");
// Step 2: upgrade to treasury contract once it is deployed locks permanently
freshLm.setFeeDestination(address(harberg));
assertTrue(freshLm.feeDestinationLocked(), "locked after contract set");
assertEq(freshLm.feeDestination(), address(harberg));
// Step 3: any further attempt reverts
vm.expectRevert("fee destination locked");
freshLm.setFeeDestination(makeAddr("attacker"));
}
/**
* @notice Once locked, setFeeDestination reverts
*/