# Resetting delegation will result in user funds being lost forever

PoolTogether TwabController treats address(0) as self-delegation on read but transfers balance to address(0) on write, permanently locking user funds when resetting delegation.

- Payout: Contest reward
- Severity: high
- Program: PoolTogether
- Credited: dirk\_y
- Disclosed: 2023-09-27
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-07-pooltogether-findings/issues/206
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-pooltogether%3AH-06
- 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:** TwabController.sol delegation logic in pt-v5-twab-controller
**Root cause:** _delegateOf maps a stored address(0) delegate to the user themselves, but _delegate writes _to=address(0) directly and _transferDelegateBalance moves the user's balance to address(0), so the read and write semantics diverge.
**Steps:**
1. Alice deposits 1000e18 into the vault.
2. Alice calls `twabController.delegate(vault, bob)` to delegate to bob.
3. Alice calls `twabController.delegate(vault, address(0))` intending to reset to self; balance is transferred to address(0).
4. Alice calls `delegate(vault, alice)`; reverts with SameDelegateAlreadySet since _delegateOf now returns alice.
5. Alice calls `delegate(vault, bob)`; also reverts.
6. Alice calls `vault.withdraw(maxWithdraw(alice), alice, alice)`; reverts with DelegateBalanceLTAmount(0, 1000e18).
**How found:** Code reading of _delegateOf revealed address(0) is interpreted as self-delegation on read, while _delegate stores _to verbatim and transfers balance to it; the mismatch between read and write semantics for the zero address suggested the reset path would misroute funds.
**Exploitation:** No attacker needed; a user following the intuitive reset-to-zero pattern self-locks all vault funds. Funds become unrecoverable because delegate balance is zeroed and no further delegation or withdrawal is possible.
**Insight:** When a sentinel value (address(0)) has special meaning in a getter, audit every setter that accepts the same field for symmetric handling; a getter that maps zero to a default while the setter writes zero raw is a classic fund-lock pattern.
