Omniscia Steer Protocol Audit

LiquidityManagerHelper Manual Review Findings

LiquidityManagerHelper Manual Review Findings

LMH-01M: Inexistent Validation of Oracle Observation Cardinality

Description:

The LiquidityManagerHelper::uniV4Volatility function does not validate that the integrated Oracle hook has a proper cardinality configured.

Impact:

A proper cardinality configuration varies per asset and is usually attached to the volatility of the asset (i.e. volatile assets should have higher cardinalities to ensure longer sample periods).

In reality, a proper alleviation would involve an initialization of some sort in the system per pool that ensures it is set to a specific cardinality based on the underlying asset's presumed volatility level.

Example:

src/helpers/LiquidityManagerHelper.sol
41/// @notice Checks if the current tick is within allowed volatility range from TWAP
42/// @param poolKey The pool key containing hook address for TWAP data
43/// @param currentTick The current tick from the pool
44/// @param twapInterval The time interval for TWAP calculation
45/// @param maxTickChange Maximum allowed tick deviation from TWAP
46function uniV4Volatility(PoolKey calldata poolKey, int24 currentTick, uint32 twapInterval, int24 maxTickChange)
47 external
48 view
49 override
50{
51 uint32[] memory secondsAgos = new uint32[](2);
52 secondsAgos[0] = twapInterval; // Δt
53 secondsAgos[1] = 0; // now
54
55 // Get the Oracle Hook from poolKey.hooks
56 IOracleHook oracleHook = IOracleHook(address(poolKey.hooks));
57
58 // Call observe on the Oracle Hook to get tickCumulatives
59 (int48[] memory tickCumulatives,) = oracleHook.observe(poolKey, secondsAgos);
60
61 // Calculate TWAP tick from tick cumulatives
62 int24 twapTick = int24((tickCumulatives[1] - tickCumulatives[0]) / int32(twapInterval));
63
64 // Check that the current tick is within the allowed range from the TWAP tick
65 require(
66 currentTick <= twapTick + maxTickChange && currentTick >= twapTick - maxTickChange,
67 "V" // "volatility" revert reason kept unchanged
68 );
69}

Recommendation:

We advise the code to mandate a minimum cardinality target, preventing pools with few observations from being considered as supported by the system.

Alleviation (121dc0b1329a48555f90bb92e58a95e8ff8a7c79):

The Steer Protocol team evaluated this exhibit and opted to acknowledge it due to the nuisances involved in being able to properly validate the cardinality of each unique asset.

LMH-02M: Improper Utilization of Checked Arithmetic

TypeSeverityLocation
Logical FaultLiquidityManagerHelper.sol:
I-1: L220
I-2: L221

Description:

The referenced calculations are meant to mimic the mechanisms of Uniswap V4 that calculate the fees due for a particular position.

The Steer Protocol team implementation will employ checked arithmetic when calculating the fee growth which is incorrect and can result in a severe Denial-of-Service for the vault due to underflows when the AMM pool is in its early stages.

Impact:

Certain pool configurations and trading activities can result in the fee growth being close to the maximum permitted and underflowing, resulting in an erroneous transaction revert in the current implementation.

Example:

src/helpers/LiquidityManagerHelper.sol
219// delta = growth since last time the position was touched
220vars.fees0 = FullMath.mulDiv(vars.feeGrowth0Inside - vars.feeGrowth0Last, vars.liquidity, FixedPoint128.Q128);
221vars.fees1 = FullMath.mulDiv(vars.feeGrowth1Inside - vars.feeGrowth1Last, vars.liquidity, FixedPoint128.Q128);

Recommendation:

We advise the relevant operations to be wrapped in an unchecked code block, ensuring that they are calculated in line with their original implementation.

Alleviation (121dc0b1329a48555f90bb92e58a95e8ff8a7c79):

An unchecked code block has been properly introduced for the referenced operations, alleviating this exhibit in full.

LMH-03M: Inexistent Rounding of TWAP

Description:

The TWAP observation implemented through the V4 oracle hook is meant to mimic the Uniswap V3 approach and should thus round toward negative infinity as well.

Impact:

The current TWAP tick calculation mechanism will round toward zero which contradicts the expected behaviour of the system for negative values.

Example:

src/helpers/LiquidityManagerHelper.sol
46function uniV4Volatility(PoolKey calldata poolKey, int24 currentTick, uint32 twapInterval, int24 maxTickChange)
47 external
48 view
49 override
50{
51 uint32[] memory secondsAgos = new uint32[](2);
52 secondsAgos[0] = twapInterval; // Δt
53 secondsAgos[1] = 0; // now
54
55 // Get the Oracle Hook from poolKey.hooks
56 IOracleHook oracleHook = IOracleHook(address(poolKey.hooks));
57
58 // Call observe on the Oracle Hook to get tickCumulatives
59 (int48[] memory tickCumulatives,) = oracleHook.observe(poolKey, secondsAgos);
60
61 // Calculate TWAP tick from tick cumulatives
62 int24 twapTick = int24((tickCumulatives[1] - tickCumulatives[0]) / int32(twapInterval));
63
64 // Check that the current tick is within the allowed range from the TWAP tick
65 require(
66 currentTick <= twapTick + maxTickChange && currentTick >= twapTick - maxTickChange,
67 "V" // "volatility" revert reason kept unchanged
68 );
69}

Recommendation:

We advise the same behaviour to be implemented hear as well, ensuring that the observed tick is correct for negative values.

Alleviation (121dc0b1329a48555f90bb92e58a95e8ff8a7c79):

The code was updated to properly round toward negative infinity, alleviating this exhibit.