# Ocean BPool: asymmetric join/exit math drains mOCEAN pools

Asymmetric BPool single-sided join/exit math plus SideStaking gulp mirroring let an attacker flash-swap mOCEAN, repeatedly join/exit pools, and drain ~127.86K mOCEAN.

- Payout: Real-world hack
- Severity: high
- Program: OceanBPoolSideStaking
- Credited: DeFiHackLabs
- Disclosed: 2026-06-25
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2026-06/OceanBPoolSideStaking_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20260625-oceanbpoolsidestaking
- Tags: domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity technique:chained vuln:accounting-error vuln:business-logic vuln:flash-loan vuln:oracle-manipulation

**Target:** Ocean BPool / SideStaking on Polygon
**Root cause:** BPool's joinswapExternAmountIn and exitswapPoolAmountIn math is asymmetric for single-sided operations, and SideStaking auto-mirrors each join/exit with datatoken stake/unstake plus gulp of stale reserves, so the attacker redeems more mOCEAN than deposited.
**Steps:**
1. Flash-swap ~99% of mOCEAN reserve from UniswapV2 pair `0xEC554b30Ca0656Ea2404e85528C1d5F885e9E296` via `swap(borrowAmount,0,...)`.
2. For each of 8 vulnerable BPools, approve mOCEAN and loop `joinswapExternAmountIn(amountIn,0)` with amountIn capped at `getBalance(mOCEAN)/2 - 1` up to 16 times.
3. Call `pool.gulp(mOCEAN)` to sync stale reserve accounting.
4. Loop `exitswapPoolAmountIn(poolAmountIn,0)` with poolAmountIn capped at `totalSupply()/4` up to 16 times to redeem mOCEAN.
5. Repay flash swap (`borrowed*1000/997+1`) and transfer remaining mOCEAN profit to attacker.
**Exploitation:** Attacker flash-borrowed nearly all mOCEAN from a UniswapV2 pair, then for each of 8 Ocean BPools performed repeated max single-sided mOCEAN joins, called gulp to sync reserves, and exited BPT back to mOCEAN. The asymmetric join/exit math combined with SideStaking's automatic stake/unstake mirroring yielded more mOCEAN out than in; profit ~127.86K mOCEAN after repaying the flash loan.
**Escalation:** Repeated join/exit loops (up to 16 each) across 8 pools amplified the per-pool imbalance into a six-figure drain.
**Insight:** When a pool auto-mirrors single-sided joins/exits into a staking contract and exposes a gulp() to sync reserves, test whether join and exit math are symmetric under repeated max-size operations — the asymmetry compounds across loops and pools.
