Wrong parameter for _resetPerAddressTracking
Description
Because of the protocol designed that each phase will have different limit and cooldown duration, thus for every address will be tracked swapAmount and lastSwapBlock inside mappping. The tracker will be reset to 0 everytime new phase is started.
However, the internal function _resetPerAddressTracking() inside TokenLaunchHook.sol using address(0) instead of user address
function _resetPerAddressTracking() internal {
addressSwappedAmount[address(0)] = 0;
addressLastSwapBlock[address(0)] = 0;
}
Risk
The absence of reset tracker will resulted user has smaller limit or cool down duration than it supposed to be. In extreme case, user will get penalty because of wrong tracker data.
Likelihood:
Impact:
Proof of Concept
Inside current test suite TokenLaunchHookUnit.t.sol add this function.
Run test suite with forge test --match-test test_PhaseTransition_TrackingFailed -vvv
function test_PhaseTransition_TrackingFailed() public {
assertEq(antiBotHook.getCurrentPhase(), 1, "Should start in phase 1");
vm.deal(user1, 10 ether);
vm.startPrank(user1);
uint128 initialliquidity = StateLibrary.getLiquidity(manager, key.toId());
console.log("Initial liquidity: ", initialliquidity);
uint256 limitphase1 = initialliquidity * 100 /10000;
console.log("Phase 1 limit is : ", limitphase1);
console.log("Phase 1 limit should be (liquidity * 100 / 10_000)");
SwapParams memory params = SwapParams({
zeroForOne: true,
amountSpecified: -int256(1 ether),
sqrtPriceLimitX96: TickMath.MIN_SQRT_PRICE + 1
});
PoolSwapTest.TestSettings memory testSettings =
PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false});
swapRouter.swap{value: 1 ether}(key, params, testSettings, ZERO_BYTES);
console.log("Swap 1 ether");
uint256 remainingLimit1 = antiBotHook.getUserRemainingLimit(address(swapRouter));
console.log("Remaining limit for phase 1:", remainingLimit1);
assertEq(remainingLimit1, (limitphase1 - 1e18));
vm.roll(block.number + phase1Duration + 1);
console.log("Jump to phase 2 (roll 101 blocks)");
console.log("Swap amount tracking should be 0 again");
assertEq(antiBotHook.getCurrentPhase(), 2, "Should be in phase 2");
uint256 limitphase2 = initialliquidity * 500 /10000;
console.log("Phase 2 limit should be (liquidity * 500 / 10_000)");
console.log("Phase 2 limit is : ", limitphase2);
uint256 remainingLimit2 = antiBotHook.getUserRemainingLimit(address(swapRouter));
console.log("Remaining limit for phase 2:", remainingLimit2);
assertEq(limitphase2, remainingLimit2);
vm.stopPrank();
}
Log output of test shown that remaining limit of phase 2 is reduce by 1 ether, where it is supposed to be max limit from phase 2 if the tracker is reset properly.
Initial liquidity: 3338502497096994491347
Phase 1 limit is : 33385024970969944913
Phase 1 limit should be (liquidity * 100 / 10_000)
Swap 1 ether
Remaining limit for phase 1: 32385024970969944913
Jump to phase 2 (roll 101 blocks)
Swap amount tracking should be 0 again
Phase 2 limit should be (liquidity * 500 / 10_000)
Phase 2 limit is : 166925124854849724567
Remaining limit for phase 2: 165925124854849724567
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 240.61ms (6.11ms CPU time)
Ran 1 test suite in 400.37ms (240.61ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)
Failing tests:
Encountered 1 failing test in test/TokenLaunchHookUnit.t.sol:TestTokenLaunchHook
[FAIL: assertion failed: 166925124854849724567 != 165925124854849724567] test_PhaseTransition_TrackingFailed() (gas: 209986)
Encountered a total of 1 failing tests, 0 tests succeeded
Recommended Mitigation
Add user address as input
-function _resetPerAddressTracking() internal {
+function _resetPerAddressTracking(address user) internal {
- addressSwappedAmount[address(0)] = 0;
- addressLastSwapBlock[address(0)] = 0;
+ addressSwappedAmount[user] = 0;
+ addressLastSwapBlock[user] = 0;
}