# SwappableYieldSource: Missing same deposit token check in transferFunds()

SwappableYieldSource.transferFunds() lacked a same-deposit-token check, letting a privileged owner redeem a more valuable token and withdraw the difference.

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

**Target:** SwappableYieldSource contract
**Root cause:** transferFunds() redeems from an arbitrary _yieldSource and supplies the resulting balance into _currentYieldSource without verifying both yield sources share the same deposit token, so token units of different value are treated as equivalent.
**Steps:**
1. Deposit 100 DAI into the swappable yield source contract
2. Call `transferFunds(_yieldSource, 100 * 1e18)` where _yieldSource holds WETH
3. _requireDifferentYieldSource() passes; _yieldSource.redeemToken(100e18) sends 100 WETH to the contract
4. currentBalance = depositToken().balanceOf(this) is ≥100 WETH; require(_amount <= currentBalance) passes
5. _currentYieldSource.supplyTokenTo(currentBalance, this) supplies the 100 DAI instead
6. Call `transferERC20(WETH, attackerAddress, 100 * 1e18)` to withdraw 100 WETH
**How found:** Code review of transferFunds() flow: noticed redemption uses _yieldSource.depositToken() balance but supply uses _currentYieldSource, with no equality check between the two deposit tokens.
**Exploitation:** A malicious owner or asset manager deposits a cheap token (DAI), calls transferFunds() pointing at a yield source holding a more valuable token (WETH), and the contract redeems WETH while only supplying the cheap DAI, then withdraws the WETH via transferERC20().
**Insight:** When a function moves value between two pluggable sources, verify the asset identity (token address/decimals) of both sides, not just the numeric amount; mismatched-token paths let privileged roles arbitrage value out of the contract.

