#  Incorrect implementation of the ETHPoolLPFactory.sol#rotateLPTokens let user stakes ETH more than maxStakingAmountPerValidator in StakingFundsVault, and DOS the stake function in LiquidStakingManager

rotateLPTokens in ETHPoolLPFactory caps new LP supply at hardcoded 24 ETH instead of maxStakingAmountPerValidator (4 ETH), letting LP supply exceed 4 ETH and permanently DOS stake().

- Payout: Contest reward
- Severity: medium
- Program: Stakehouse Protocol
- Credited: ladboy233
- Disclosed: 2023-01-20
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-11-stakehouse-findings/issues/132
- Library page: https://bugbountylibrary.com/r/c4%3A2022-11-stakehouse%3AM-10
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** ETHPoolLPFactory.rotateLPTokens / StakingFundsVault LP tokens
**Root cause:** rotateLPTokens checks `_amount + _newLPToken.totalSupply() <= 24 ether` (hardcoded) instead of `maxStakingAmountPerValidator` (4 ether), so LP supply for a knot can exceed 4 ETH. _assertEtherIsReadyForValidatorStaking then requires totalSupply() == 4 ether exactly, so staking reverts.
**Steps:**
1. Deposit 4 ETH into StakingFundsVault for BLS key A and 4 ETH for key B via `depositETHForStaking`.
2. Wait >30 minutes (lastInteractedTimestamp freshness check).
3. Call `stakingFundsVault.rotateLPTokens(lpA, lpB, 4 ether)` — passes the 24 ETH cap, lpB totalSupply becomes 8 ETH.
4. Call `stake(...)` for key B; `_assertEtherIsReadyForValidatorStaking` reverts on `require(stakingFundsLP.totalSupply() == 4 ether)`.
**How found:** Code reading: noticed rotateLPTokens uses a hardcoded 24 ether cap while _depositETHForStaking enforces maxStakingAmountPerValidator=4 ether, and that stake() requires exact equality of 4 ether LP supply — mismatch between the two limits.
**Exploitation:** Any LP holder rotates their LP from one knot to another, inflating the destination knot's LP supply above 4 ETH; the strict equality check in _assertEtherIsReadyForValidatorStaking then blocks staking for that knot, permanently DOSing it.
**Insight:** When a protocol enforces a per-validator cap in one path (deposit) but a different hardcoded constant in another (rotate), the invariant checked downstream with `==` becomes breakable; look for duplicated limit constants across mint paths.
