# Anyone can get swaps for free given certain conditions in swap.

LibSwap.swap skips pulling user funds when contract already holds enough of the sending token, letting anyone swap using LI.FI's latent balance.

- Payout: Audit contest
- Severity: medium
- Program: LI.FI
- Found by: hake
- Disclosed: 2022-05-05
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-03-lifinance-findings/issues/66
- Library page: https://bugbountylibrary.com/r/c4%3A2022-03-lifinance%3AM-02
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Solidity swap library / GenericSwapFacet
**Root cause:** swap() only transfers fromAmount from msg.sender when the contract's own balance of the sending asset is below fromAmount; if latent funds already cover it, the transfer is skipped and the swap is funded by the contract's balance.
**Steps:**
1. Ensure LI.FI contract holds a non-native ERC20 balance (latent funds from prior ops).
2. Call `swapTokensGeneric` with `_swapData.fromAmount` just below `LibAsset.getOwnBalance(fromAssetId)`.
3. First `if` in `swap` is skipped, so no `transferFromERC20` from attacker occurs.
4. Swap executes, increasing receiving asset balance; delta is transferred to attacker.
**How found:** Code reading of LibSwap.swap revealed the balance-gated transferFrom condition, implying the contract's own holdings can substitute for user funds.
**Exploitation:** Attacker monitors the LI.FI diamond for leftover ERC20 balances, then submits a swap with fromAmount just under the contract's own balance so the transferFrom is bypassed; the swap output delta is paid out to the attacker, draining latent funds up to slippage limits.
**Insight:** When a contract gates user deposits on `ownBalance < amount`, leftover/latent balances become spendable by anyone; check swap/bridge libraries for balance-conditional pulls rather than unconditional transferFrom.
