# setYieldSource leads to temporary wrong results

After setYieldSource swaps the yield source without moving balances, supplyTokenTo mints inflated shares from the stale balance, letting an attacker drain funds.

- Payout: Audit contest
- Severity: high
- Program: PoolTogether
- Found by: gpersoon
- Disclosed: 2021-09-15
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2021-07-pooltogether-findings/issues/4
- Library page: https://bugbountylibrary.com/r/c4%3A2021-07-pooltogether%3AH-03
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:race-window technique:source-review vuln:accounting-error vuln:business-logic vuln:share-inflation

**Target:** SwappableYieldSource Solidity contract
**Root cause:** setYieldSource changes yieldSource but does not transfer underlying balances, so yieldSource.balanceOfToken(address(this)) reflects only newly supplied tokens while totalSupply stays unchanged, corrupting the share exchange rate.
**Steps:**
1. Owner/asset manager calls `setYieldSource(_newYieldSource)`; balances remain in old source, shares unchanged.
2. Attacker monitors chain for the setYieldSource tx and immediately calls `supplyTokenTo(amount, to)` (no access control).
3. Contract calls `yieldSource.supplyTokenTo(amount, address(this))` then `_mintShares`, which computes shares via `_tokenToShares` using `yieldSource.balanceOfToken(address(this))` that excludes old-source tokens.
4. Attacker receives more shares than appropriate; after `transferFunds` moves old balances, redeem inflated shares to drain funds.
**How found:** Code review of the setYieldSource/transferFunds split: noticed the two-step migration leaves an inconsistent window where balanceOfToken and _tokenToShares read an incomplete yieldSource balance while totalSupply is unchanged.
**Exploitation:** Attacker watches for setYieldSource, front-runs the balance transfer by calling supplyTokenTo with a small deposit, gets inflated shares because the exchange rate is computed against a near-empty new yield source, then redeems after transferFunds restores the full balance.
**Insight:** When a contract migrates between backing sources in two steps, check every share/asset conversion for reads of the not-yet-migrated balance during the window; permissionless deposit/mint functions in that window mint mispriced shares.

