On 2026-08-31, an attacker on Ethereum drained a Balancer V1 BPool of ~$110,839 by compressing the WBTC reserve and looping single-asset joins for one satoshi at a time, part of an aggregate ~$234K drain across five pools.
Logged as “2026-08-31: Joinswappoolamountout Rounding Drain Across 5 Pools on BalancerV1BPool”.
A Balancer V1 BPool priced single-asset joins through calcSingleInGivenPoolOut in 18-decimal fixed point, then accepted the caller's tokenAmountIn so long as it was non-zero, at most maxAmountIn, and at most balance * MAX_IN_RATIO. There was no minimum-effective-input or relative-error check. MIN_BALANCE was enforced only in bind and rebind, never on the join math. Once the WBTC reserve was compressed to a couple of satoshi by ordinary public swaps, the required WBTC input for a sizable BPT mint rounded down to a single satoshi (eight-decimal WBTC against 18-decimal weight math), but the full BPT was still minted.
The attacker (EOA 0x338c7ec9befbb451d66fd8a468c32184f5689a41, via contract 0x9caa8d0e44b22f50057d2f4ce0d1446529e11be3) ran the drain in a single transaction on block 25872274 of Ethereum (0x72510b257cc09bde8435b83ac1636f9498ffc353583330600b5b8da43d0d1aff). The victim BPool at 0x2257aaac34bcb27900291f7b84ee2565a6cbac57 held four assets at 12.5e18 denorm weights each: DPI, USDC, WETH, and WBTC. The transaction contained 290 BPool calls in three phases.
The first phase, 38 swapExactAmountIn calls followed by 3 swapExactAmountOut calls, compressed the WBTC reserve toward dust. The second phase, ~100 paired joinswapPoolAmountOut(WBTC, pao, maxIn=1) followed by exitswapPoolAmountIn(WBTC, pai, minOut=1), minted a large BPT share for one satoshi of WBTC each round and then pulled that satoshi back out, so the next join rounded to dust again. The net effect is that the attacker accumulated essentially the entire BPT supply for dust. The third phase, 44 swapExactAmountOut calls followed by 1 exitPool, redeemed the accumulated ~99.9 percent of the BPT supply for a proportional cut of the pool's real DPI, USDC, WETH, and WBTC.
The README totals the incident at ~$110,839 for this DPI/USDC/WETH/WBTC pool. SlowMist's headline of ~$234K is the aggregate across five pools the same attacker hit through the same rounding bug the same day. Working capital was sourced from nested Spark/Aave, Morpho, and Uniswap V3 flash loans, all repaid within the transaction.
The fix is to size tokenAmountIn against the BPT out using more than 18-decimal math for assets whose decimals are fewer, or to enforce a minimum ratio of tokenAmountIn to tokenBalance on every join. The cleaner pattern in modern AMMs is to use the full-asset-decimals math throughout, including in the price-impact check that BPool never applied.
Query every incident yourself — free, no signup
Updated 14 Oct 2026. Figures are as reported by the sources listed above and are not independently verified.