# Unstaking does not update the mapping sETHUserClaimForKnot

Unstaking sETH in Syndicate fails to rebase sETHUserClaimForKnot, so remaining stakers are under-credited or blocked from claiming owed ETH.

- Payout: Contest reward
- Severity: high
- Program: Stakehouse Protocol
- Credited: HE1M
- Disclosed: 2023-01-20
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-11-stakehouse-findings/issues/90
- Library page: https://bugbountylibrary.com/r/c4%3A2022-11-stakehouse%3AH-04
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Syndicate.sol staking/claim accounting contract
**Root cause:** unstake() reduces sETHStakedBalanceForKnot but never rescales sETHUserClaimForKnot, leaving the claim checkpoint based on the pre-unstake balance.
**Steps:**
1. Alice stakes 5 sETH via `stake(...)`; sETHUserClaimForKnot[BLS][Alice] = 5e18*accumulatedETHPerFreeFloatingShare/PRECISION, balance=5e18.
2. Alice calls `unstake(...)` for 3 sETH; owed ETH paid, balance becomes 2e18, total stake decremented, but sETHUserClaimForKnot unchanged.
3. More ETH accrues per free floating share for the BLS key.
4. Alice calls `claimAsStaker(...)` or `unstake(...)`; `calculateUnclaimedFreeFloatingETHShare` computes `(newAccumulatedETHPerShare*2e18)/PRECISION - (5e18*oldAccumulated)/PRECISION`, which underflows/under-credits.
**How found:** Code reading of the stake/unstake/claim accounting: noticed unstake updates sETHStakedBalanceForKnot and sETHTotalStakeForKnot but not sETHUserClaimForKnot, then traced calculateUnclaimedFreeFloatingETHShare to confirm the mismatch.
**Exploitation:** Not an attacker-gain path; a staker who unstakes part of their position is denied or shortchanged on subsequent ETH claims because the claim checkpoint still reflects the larger prior balance.
**Insight:** In reward-per-share accounting, every balance mutation (including partial withdrawals) must re-checkpoint the user's claim accumulator; grep for balance decrements that don't touch the corresponding userClaim mapping.
