Description
The addReHypothecatedLiquidity and removeReHypothecatedLiquidity methods accept only a shares parameter and have no slippage protection. This exposes users to sandwich attacks and unfavorable price movements.
When totalSupply() == 0, _sharesToAmounts reads the current pool price via getSlot0 to determine the deposit ratio. When totalSupply() > 0, amounts are computed proportionally from yield source balances, which also fluctuate. In both cases, the amounts a user actually transfers can differ significantly from what they expected at the time of signing the transaction.
A malicious actor can sandwich a deposit or withdrawal by manipulating the pool price or yield source state before the victim's transaction, causing the user to deposit more tokens (or receive fewer) than intended.
Insufficient Warning
The contract acknowledges slippage risk in a WARNING comment:
WARNING: Liquidity additions and removals may be affected by slippage. Users can protect against unexpected slippage in general by verifying the amount received is as expected, using a wrapper that performs these checks.
This suggests users should verify amounts via an external wrapper. However, the slippage does not occur in the yield source interaction but earlier, in _sharesToAmounts, which converts shares into amount0 and amount1:
- When
totalSupply() == 0, the conversion reads the current pool price via getSlot0. An attacker can manipulate the pool price before the victim's transaction, causing a skewed deposit ratio (e.g., far more ETH than expected relative to USDC).
- When
totalSupply() > 0, the conversion uses _getAmountInYieldSource for each currency. These balances shift whenever _afterSwap → _resolveHookDelta rebalances tokens between the pool and yield sources, so a swap landing right before the victim's transaction changes the ratio.
By the time _depositToYieldSource or _withdrawFromYieldSource is called, the amounts are already determined — the user has committed to a potentially unfavorable ratio within the same atomic call. There is no external hook point between the share-to-amount conversion and the token transfer where a wrapper could intercept and revert.
Slippage protection should be enforced at the contract level with minimal overhead, not deferred to implementors.
Suggested fix
Add slippage parameters to both functions. Two possible approaches:
Option A — Amount-based (simpler)
function addReHypothecatedLiquidity(
uint256 shares,
uint256 amount0Max,
uint256 amount1Max
) ...
function removeReHypothecatedLiquidity(
uint256 shares,
uint256 amount0Min,
uint256 amount1Min
) ...
Check that the computed amounts are within the user's bounds before executing transfers. This is consistent with standard Uniswap V4 periphery patterns.
Option B — Price-based
function addReHypothecatedLiquidity(
uint256 shares,
uint160 expectedSqrtPriceX96,
uint24 maxPriceSlippage
) ...
Check that the current pool price hasn't deviated beyond the user's tolerance before any state changes. This protects against sandwich attacks at the source.
Either approach should revert before any token transfers or share minting/burning if the slippage check fails.
Context
We built a production rehypothecation hook (Alphix) on top of this pattern and encountered this exact issue. We implemented price-based slippage protection with full test coverage including sandwich attack scenarios. Happy to contribute a PR if the team has a preferred approach.
Description
The
addReHypothecatedLiquidityandremoveReHypothecatedLiquiditymethods accept only asharesparameter and have no slippage protection. This exposes users to sandwich attacks and unfavorable price movements.When
totalSupply() == 0,_sharesToAmountsreads the current pool price viagetSlot0to determine the deposit ratio. WhentotalSupply() > 0, amounts are computed proportionally from yield source balances, which also fluctuate. In both cases, the amounts a user actually transfers can differ significantly from what they expected at the time of signing the transaction.A malicious actor can sandwich a deposit or withdrawal by manipulating the pool price or yield source state before the victim's transaction, causing the user to deposit more tokens (or receive fewer) than intended.
Insufficient Warning
The contract acknowledges slippage risk in a
WARNINGcomment:This suggests users should verify amounts via an external wrapper. However, the slippage does not occur in the yield source interaction but earlier, in
_sharesToAmounts, which convertssharesintoamount0andamount1:totalSupply() == 0, the conversion reads the current pool price viagetSlot0. An attacker can manipulate the pool price before the victim's transaction, causing a skewed deposit ratio (e.g., far more ETH than expected relative to USDC).totalSupply() > 0, the conversion uses_getAmountInYieldSourcefor each currency. These balances shift whenever_afterSwap→_resolveHookDeltarebalances tokens between the pool and yield sources, so a swap landing right before the victim's transaction changes the ratio.By the time
_depositToYieldSourceor_withdrawFromYieldSourceis called, the amounts are already determined — the user has committed to a potentially unfavorable ratio within the same atomic call. There is no external hook point between the share-to-amount conversion and the token transfer where a wrapper could intercept and revert.Slippage protection should be enforced at the contract level with minimal overhead, not deferred to implementors.
Suggested fix
Add slippage parameters to both functions. Two possible approaches:
Option A — Amount-based (simpler)
Check that the computed amounts are within the user's bounds before executing transfers. This is consistent with standard Uniswap V4 periphery patterns.
Option B — Price-based
Check that the current pool price hasn't deviated beyond the user's tolerance before any state changes. This protects against sandwich attacks at the source.
Either approach should revert before any token transfers or share minting/burning if the slippage check fails.
Context
We built a production rehypothecation hook (Alphix) on top of this pattern and encountered this exact issue. We implemented price-based slippage protection with full test coverage including sandwich attack scenarios. Happy to contribute a PR if the team has a preferred approach.