User tracking metrics are not reset during phase transitions
Description
The protocol tracks user swap amounts and cooldowns to enforce limits that vary by phase. The design intends for these limits to reset when the protocol transitions from Phase 1 to Phase 2.
The function _resetPerAddressTracking is called during a phase transition to achieve this. However, it incorrectly resets the mapping for address(0) instead of msg.sender or iterating through users (which is not possible in this architecture). As a result, a user's addressSwappedAmount accumulates across phases. A user who swapped 1% in Phase 1 will immediately be at 1% usage in Phase 2, potentially triggering penalties prematurely if they were expected to have a fresh limit.
function _resetPerAddressTracking() internal {
@> addressSwappedAmount[address(0)] = 0;
@> addressLastSwapBlock[address(0)] = 0;
}
Risk
Likelihood:
Impact:
Proof of Concept
function test_Bug_ResetTrackingFailed() public {
SwapParams memory params = SwapParams({
zeroForOne: true,
amountSpecified: -0.001 ether,
sqrtPriceLimitX96: TickMath.MIN_SQRT_PRICE + 1
});
PoolSwapTest.TestSettings memory testSettings =
PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false});
vm.deal(user1, 1 ether);
vm.prank(user1);
swapRouter.swap{value: 0.001 ether}(key, params, testSettings, ZERO_BYTES);
uint256 amountPhase1 = antiBotHook.addressSwappedAmount(address(swapRouter));
vm.roll(block.number + phase1Duration + 1);
vm.prank(user1);
swapRouter.swap{value: 0.001 ether}(key, params, testSettings, ZERO_BYTES);
uint256 amountPhase2 = antiBotHook.addressSwappedAmount(address(swapRouter));
assertEq(amountPhase2, amountPhase1 + 0.001 ether, "BUG: Address tracking not reset on phase transition");
}
Recommended Mitigation
Update state variables to map Phase ID -> User Address -> Data instead of reset.
- mapping(address => uint256) public addressSwappedAmount;
- mapping(address => uint256) public addressLastSwapBlock;
+ // Mapping: PhaseID => UserAddress => Data
+ mapping(uint256 => mapping(address => uint256)) public addressSwappedAmount;
+ mapping(uint256 => mapping(address => uint256)) public addressLastSwapBlock;
function _beforeSwap(...) {
// ... phase calculation ...
- uint256 currentAmount = addressSwappedAmount[sender];
+ uint256 currentAmount = addressSwappedAmount[currentPhase][sender];