# Existing balance of underlying tokens in omnipool.sol skews target allocation

Omnipool depositFor counts stray underlying token balance in the contract, inflating target allocation and skewing deposit splits across pools.

- Payout: Contest reward
- Severity: high
- Program: Opal
- Credited: giraffe0x
- Disclosed: 2024-03-30
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_opal_feb2024.pdf#3.2.10
- Library page: https://bugbountylibrary.com/r/cantina%3Aopal_feb2024%3A3.2.10
- Tags: domain:web3 impact:integrity kind:contest platform:cantina sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Omnipool.sol depositFor / _getDepositPool allocation logic
**Root cause:** depositFor computes beforeAllocatedBalance as totalUnderlying_ + underlyingToken.balanceOf(address(this)), so any idle/donated underlying inflates totalUnderlying_ and thus targetAllocation_ in _getDepositPool, producing an oversized maxDepositAmount for one pool.
**Steps:**
1. Seed Omnipool with 100 USDC across two 50/50 pools.
2. Transfer (donate) 10 USDC directly to the Omnipool contract address.
3. Alice calls `pool.deposit(100e6, 0)`.
4. totalUnderlying_ = 100+10+100 = 210; targetAllocation = 105; currentAlloc = 50; maxDeposit = 55.
5. Deposit splits 55 USDC to pool1 and 45 to pool2, leaving pools imbalanced.
**How found:** Code review of depositFor noticed underlyingToken.balanceOf(address(this)) added into totalUnderlying_, then traced how _getDepositPool uses that value to compute targetAllocation_ and maxDepositAmount_, hypothesizing stray balances would skew allocation.
**Exploitation:** Attacker donates a small amount of underlying to the Omnipool contract, then makes a large deposit; the inflated targetAllocation causes the deposit to be routed disproportionately to one pool, leaving the pool imbalanced and forcing Opal to spend Gem tokens on rebalancing rewards.
**Insight:** When auditing vault/deposit allocators, check whether 'total assets' is derived from live token balanceOf rather than internal accounting; any externally-increasable balance (donations, dust, stuck withdrawals) becomes an input an attacker can manipulate to steer allocation.
