Description
-
The contract uses initialLiquidity to calculate swap limits: maxSwapAmount = (initialLiquidity * phaseLimitBps) / 10000
-
initialLiquidity is set by calling StateLibrary.getLiquidity(), which returns the pool's liquidity value (L) in Uniswap's concentrated liquidity formula, not actual token amounts.
function _afterInitialize(address, PoolKey calldata key, uint160, int24) internal override returns (bytes4) {
uint128 liquidity = StateLibrary.getLiquidity(poolManager, key.toId());
initialLiquidity = uint256(liquidity);
}
function _beforeSwap(...) internal override returns (...) {
if (initialLiquidity == 0) {
uint128 liquidity = StateLibrary.getLiquidity(poolManager, key.toId());
initialLiquidity = uint256(liquidity);
}
uint256 maxSwapAmount = (initialLiquidity * phaseLimitBps) / 10000;
}
Risk
Likelihood:
Impact:
-
Swap limits may not align with actual token amounts in the pool
-
Depending on the price tick, the same "L" value represents different token amounts
-
Limits could be unexpectedly high or low relative to actual token supply
Proof of Concept
The limit is calculated from pool's L value, which doesn't directly map to token amounts.
function test_LiquidityVsTokenAmount() public {
uint256 liquidityL = antiBotHook.initialLiquidity();
uint256 maxSwap = (liquidityL * 100) / 10000;
console.log("Liquidity L:", liquidityL);
console.log("Max swap (1% of L):", maxSwap);
}
Recommended Mitigation
Calculate actual token amount from L and price, or accept initial supply as constructor param.
// Option 1: Use actual token balance for one side
function _afterInitialize(address, PoolKey calldata key, uint160 sqrtPriceX96, int24) internal override returns (bytes4) {
// ...
- uint128 liquidity = StateLibrary.getLiquidity(poolManager, key.toId());
- initialLiquidity = uint256(liquidity);
+ // Calculate actual token amount based on liquidity and price
+ uint128 liquidity = StateLibrary.getLiquidity(poolManager, key.toId());
+ // For currency1 (the launched token), calculate actual amount
+ uint256 tokenAmount = FullMath.mulDiv(liquidity, sqrtPriceX96, 2**96);
+ initialLiquidity = tokenAmount;
// ...
}
// Option 2: Accept a constructor parameter for initial supply
+ uint256 public immutable initialTokenSupply;
+
+ constructor(..., uint256 _initialTokenSupply) {
+ initialTokenSupply = _initialTokenSupply;
+ // Use this instead of querying pool liquidity
+ }