CryptoReal
CASE FILE — Nov 14, 2025

The One-Directional Rounding Bug That Cost Balancer $128 Million Across Nine Chains

In just over an hour on November 3rd, an attacker drained more than $128 million from Balancer's Composable Stable Pools spread across multiple blockchains, in what PeckShield's live tracker flagged as one of the largest DeFi exploits of 2025. The root cause traced back to a single design choice: a scaling function that always rounded in one direction, regardless of context — a decision Balancer's own developers had described in a code comment as carrying "minimal" impact.

Balancer had operated since 2020 and processed billions of dollars in volume without an incident of this scale. In 2022, Certora had formally verified core solvency properties of Balancer V2, confirming that BPT (Balancer Pool Token) supply could never exceed total underlying assets and that new BPT could not be minted without corresponding deposits. Those proofs, however, never examined rounding-direction risk. Separately, Trail of Bits had raised similar rounding concerns in Balancer's Linear Pools roughly four years before the attack. The gap between provable "aggregate conservation of balances" at a high level and the low-level arithmetic reality of the code turned out to be exactly where the attacker operated.

01How the discovery and response unfolded

The timeline, reconstructed from on-chain data and public statements, began at 07:46 UTC, when Hypernative's monitoring flagged unusual swap activity moving through Balancer's Composable Stable Pools. About thirty minutes later, PeckShield posted a public warning: "Hi Balancer, you may want to take a look." Five minutes after that, PeckShield followed up with a dollar figure: $70.8 million already drained. Lookonchain's own tracking climbed in near-real time, from $98 million to $116.6 million within minutes. Certora's engineers were reportedly already examining the code, trying to determine whether this was an access-control failure, a reentrancy bug, or something novel.

Within twenty minutes of the initial alert, Hypernative's emergency controls had triggered across every affected network, and a minute after that every Composable Stable Pool v6 (CSPv6) that Balancer could pause had been frozen. Recovery Mode was activated and the factory contract responsible for deploying vulnerable pools was disabled. But the response hit a structural limit: Composable Stable v5 pools had pause windows that had already expired, leaving years-old contracts — still carrying millions in liquidity — with no way to be halted. Balancer's team coordinated a cross-chain war room for containment and communications while the attacker continued moving through pool after pool on Ethereum, Base, Arbitrum, Polygon, Avalanche, Gnosis, Berachain, Sonic, and Optimism, replicating the same exploit pattern on each chain.

More than eight hours after the first alert, Balancer's official account publicly confirmed the incident: "Today, around 7:48 AM UTC, an exploit affected Balancer V2 Composable Stable Pools." By then PeckShield's running total had reached $128.64 million.

02Individual chains improvised their own defenses

Roughly two hours into the attack, Berachain's validators took the unusual step of halting the entire chain rather than pausing a single protocol. Berachain's BEX exchange had been built on Balancer v2 code; $12.86 million was rescued by a white hat during the exploit, and the network executed an emergency hard fork to reverse the remaining damage, with the affected funds recovered afterward.

Sonic Labs rolled out a new security mechanism on its Beets Protocol mid-incident, freezing the attacker's addresses and zeroing their balances. Gnosis restricted outbound bridge transfers to stop funds from leaving the chain, and Polygon's validators began outright censoring the attacker's transactions, effectively freezing the stolen assets through social coordination rather than any code-level mechanism.

Some funds were also clawed back through automated and manual intervention: StakeWise ran emergency multisig transactions to recover 5,041 osETH (about $19 million) and 13,495 osGNO (about $1.7 million) — roughly 75% of what had been taken from its pools. Separately, BitFinding's bots intercepted an additional $600,000, and MEV bots on Base recovered $150,000 more.

03Copycats arrived within the hour

Because the attacker's auxiliary math-helper contract was deployed on-chain and publicly readable, it effectively doubled as a tutorial. Within about an hour of the original exploit, imitators began launching their own attempts by swapping in a different pool address and sender address and redeploying the same logic. At least 27 forks of Balancer V2 carried the identical flaw, and while many held live liquidity, not every one of them was hit. Tikkala Security later reported that copycat attacks were still occurring a full week after the original incident.

04The technical flaw: a scaling function that only rounded one way

The vulnerability lived in a routine called _upscale(), defined in BaseGeneralPool.sol and executed ahead of every swap, after access checks, flash-loan guards, and reentrancy protections had already passed. Its job was mundane: normalize tokens with different decimal precision — USDC's 6, DAI's 18, WBTC's 8 — up to a common 18-decimal scale so Balancer's invariant math could operate consistently.

Balancer's engineers clearly understood rounding mattered, since they had built a dedicated library, FixedPoint, with explicit mulUp (round up) and mulDown (round down) functions. The intended pattern favored the protocol: round down when the pool received tokens, round up when it sent them out. But _upscale() broke that pattern — it called mulDown unconditionally, in every context, rounding the same direction whether that favored the protocol or not.

The reasoning was spelled out directly in the code, in ScalingHelpers.sol: "Upscale rounding wouldn't necessarily always go in the same direction... This is the only place where we round in the same direction for all amounts, as the impact of this rounding is expected to be minimal." The developers chose mulDown and documented why. For the overwhelming majority of swaps, that assumption held.

05From rounding quirk to extraction mechanism

When a user swaps Token A for Token B, the pool scales the input up to 18 decimals, runs the invariant math, and scales the result back down to Token B's native decimal count. If Token B uses 6 decimals and the calculation yields 1,234,567 scaled units, converting back means dividing by 10^12 — an operation that produces a remainder, and a remainder means a rounding decision has to be made.

Conventional AMM design rounds against the user and in favor of the pool whenever precision is lost, as Certora's writeup notes. Balancer's _upscale(), however, rounded down before the invariant was even calculated, meaning the pool's internal math started from numbers that were already slightly understated. In an ordinary trade, that discrepancy is trivial — smaller than typical slippage or gas costs. But Composable Stable Pools are not ordinary pools, and the attacker specifically targeted their unusual features.

The pools' signature design let LP tokens (BPT) trade as assets within the pool itself — a user could swap DAI directly for BPT in one transaction, enabling recursive liquidity movement without an explicit withdrawal step. Combined with Balancer's deferred-settlement architecture, where token transfers don't finalize until a batch transaction completes, this created the conditions for abuse. The attacker used Balancer's internal-balance accounting to briefly hold BPT inside a single batchSwap call — effectively a deficit or "internal credit" position — then used those temporary BPT claims to swap for underlying tokens, pushing pool balances toward low, edge-case levels before the transaction settled. Analysts have described this as functionally equivalent to a transaction-local "flash mint" of BPT made possible by the Vault's internal accounting.

The attack sequence, step by step

  1. Deploy a helper contract. A separate contract handled the complex precision math, sidestepping Solidity's stack-depth limits.
  2. Mint BPT without deposits. Using Balancer's composability, the attacker generated LP tokens without actually supplying assets.
  3. Push the pool toward minimum liquidity. Swapping BPT for underlying tokens drove pool balances to the edge cases where rounding errors become significant.
  4. Target the worst-case rounding combinations. Because _upscale() always rounds down via mulDown, each individual swap slightly understated the invariant — an effect amplified by choosing token and decimal-scale pairs that maximized the remainder.
  5. Repeat at scale. The attacker looped this micro-swap pattern dozens of times inside one transaction — on-chain traces show more than 65 micro-swaps — letting small per-iteration losses compound into a materially deflated invariant.
  6. Exploit the resulting mismatch. With the invariant desynchronized from reality, the BPT the attacker held was now worth more than the pool's actual assets could support.
  7. Redeem for profit. Burning the inflated BPT for real underlying tokens left the pool insolvent.

Every individual step was a technically valid contract call — no reentrancy, no leverage tricks, just arithmetic pushed to its edges by someone who understood the math better than the people who wrote it.

06Two transactions, two roles

The attack was typically split into two on-chain transactions. The first executed the rounding-manipulation loop and drained value into Balancer's internal balance ledger, where it wasn't visible to external observers — no profit appeared to move, and nothing looked obviously wrong to automated monitors. The second transaction converted that internal position into real tokens by calling manageUserBalance(WITHDRAW_INTERNAL), at which point the funds left the protocol entirely.

07Attacker addresses and contracts

Ethereum

Arbitrum

Base

Optimism (Beethoven X)

Polygon

Sonic (Beets)

Consolidation address: 0x872757006b6f2fd65244c0a2a5fdd1f70a7780f4 (Arbitrum profits)

Sums referenced in this case file

Attack contracts:

08Damage by chain

Ethereum — the largest single loss

Nearly 25,000 ETH was drained across several pools.

Pools affected:

Ethereum total: 24,733 ETH, worth roughly $91.5 million at the time.

Arbitrum

wstETH/rETH/cbETH — Pool ID 0x4a2f6ae7f3e5d715689530873ec35593dc28951b000000000000000000000481, contract 0x4a2F6Ae7F3e5D715689530873ec35593Dc28951B. Drained: 462 ETH.

Proceeds were consolidated to 0x872757006b6f2fd65244c0a2a5fdd1f70a7780f4 and bridged back to Ethereum via Stargate. Arbitrum total: 462 ETH, worth $1.7 million at the time.

Base

Attack contract: 0x56e5Adab68b594B0c2aD6C112D94AE5aCA98A001. Primary attack transaction: 0x29135f912d67db38478d0be70b9f2a1fab3b121b74d776f835ac66d6df134ec5

Base total: 42 ETH (roughly $155,000 at $3,700/ETH).

Optimism (Beethoven X)

Attack transaction: 0x3c9d2d16404a79feed9876a79f168af334726ad3ee1371f581d50ebebfe6b8c6. Withdrawal transaction: 0xbd417633433e45c1dddf9fac7680f86dfde832c07b93f4de5ce69c6312d19381. Total: roughly $1.3 million.

Polygon

Attack transaction: 0x167993d4cc39771923a6cd11d2d6e73a1b68c7464ea3c76ba41fbd32df7a96da. Withdrawal transaction: 0x9630b26a49c451365989cbd2d9696ea3bdf02505bcb297b6239f330f114c9673. Total: roughly $390,000.

Sonic (Beets)

Attack transaction: 0xd7996c8e187b9bd539a04a4f39de4d8c7c1670c601134329937738b4dfa6f8ad. Withdrawal transaction: 0xc0cc599fa5c1ec2a43a96b018fd653783cf8dd3e6f670f94961c89b61ce8c0f9. The attacker moved 19.5 million stS (about $3 million) to 0x0e9c9473D0c504Da72763426719F6f03A15544D5 using permit() and transferFrom(), then swapped into WBTC and bridged to Ethereum via LayerZero. Sonic total: $3.44 million.

Berachain (BEX)

$12.86 million was actively rescued by white hats after validators halted the chain and pushed through an emergency hard fork to reverse the damage. Berachain total: $12.86 million, fully recovered.

09Reconciling the totals

Primary exploiter haul: Ethereum 24,733 ETH ($91.5M), Arbitrum 462 ETH ($1.7M), Base 42 ETH ($155K) — subtotal 25,237 ETH (~$93.4M).

Fork-related activity: Sonic/Beets $3.44M, Berachain/BEX $12.86M (recovered), Optimism/Beethoven X ~$1.3M, Polygon ~$390K, plus unconfirmed smaller amounts reportedly on Gnosis and Avalanche that have not been publicly detailed — fork subtotal roughly $18 million.

Total stolen across the incident is put at approximately $128 million, the figure cited by PeckShield and treated as industry consensus. Independent forensic tracing accounts for about $111 million in confirmed primary-attacker withdrawals, leaving a gap of roughly $17 million attributed to copycat attacks and the undisclosed Gnosis/Avalanche losses. PeckShield's $128 million figure likely reflects the fuller ecosystem-wide picture, including copycats and minor chains, rather than just the original attacker's take.

10Where the stolen funds sit now

As of reporting, roughly $37 million remained visible in known attacker-controlled wallets:

11The copycat wave, in detail

The first copycat transaction landed just 53 minutes after the original attack, at 08:39 UTC: 0x14fb45dd869208edffcb221add152a20292283be172ddb6ccfd2d73e3710b6f4. This was possible because the attacker's math-helper contract had been deployed on-chain with full, readable source code, including all calculation logic and even Balancer's custom error types — effectively a ready-made exploitation kit for anyone able to read Solidity. All that remained was to swap in a target pool address and a new sender address. At least 27 Balancer v2 forks carried the identical vulnerability, and some were hit in the hours that followed.

12Whitehat recoveries

Combined, roughly $38.4 million was recovered or frozen across these efforts.

13Audit history: what was proven, and what wasn't

Balancer's contracts had been reviewed repeatedly since 2020 by OpenZeppelin, Trail of Bits, Certora, and ABDK Consulting — more than a dozen audit reports in total, plus formal verification work and a long-running Immunefi bug bounty program.

Certora's 2022 review of Balancer V2 Stable Pools proved high-level solvency: BPT supply could never exceed total assets, minting BPT always required a matching asset increase, and aggregate balances were conserved. Trail of Bits, in its 2021 audit, had flagged a related rounding concern in Linear Pools under finding TOB-BALANCER-004, but could not determine at the time whether it was actually exploitable given how those pools were configured; the firm flagged it anyway, based on similar findings elsewhere, and recommended fuzz testing to confirm rounding directions matched expectations across all arithmetic operations.

According to OpenZeppelin's post-incident analysis, the vulnerable pattern was first introduced on July 16, 2021, when MetaStablePool overrode the _scalingFactors function (commit 059284e). The same pattern was carried into LinearPool on September 1, 2021 (commit 4e9e70a), and into StablePhantomPool — later renamed ComposableStablePool — on September 20, 2021 (commit f450760). OpenZeppelin notes that none of the prior audits had covered these specific pools. Composable Stable Pool relied on the same shared scaling utility as the earlier pool types — the _upscale() helper calling FixedPoint.mulDown — carrying the "minimal impact" comment along with it.

Certora's own analysis later identified the properties that would have caught the bug: a roundtrip swap invariance check (swapping Token A to Token B and back should never return more than the original amount — a violation reveals compounding rounding asymmetries, exactly the kind that becomes catastrophic across 65-plus iterations in one transaction), and a BPT share-value invariant ("for any user operation, the share value of a single BPT must not decrease"), which would catch exactly this kind of desynchronization between total assets and total supply. Certora's 2022 audit had abstracted away the underlying StableMath functions to simplify its proofs, and consequently never tested numeric precision under extreme low-liquidity or edge-case conditions. As the firm put it afterward: "Solvency proofs are not sufficient. Aggregate conservation of balances does not imply rounding safety."

Trail of Bits' 2021 review reflected the threat model of its time — access control, reentrancy, phishing — with rounding treated as a moderate, somewhat underemphasized risk rather than a top-tier concern, since precision-based exploits were not yet widespread. That changed by 2023–2024, when precision-loss exploits became a recognizable pattern, claiming both Hundred Finance and Onyx Protocol. By 2025, Abracadabra and Bunni had also been hit by comparable rounding-based attacks earlier in the year — establishing rounding-edge exploitation as an established playbook well before Balancer was hit.

14Market and governance fallout

Balancer's BAL token fell 5% in the immediate aftermath, and protocol TVL dropped 46% within 24 hours, from $626 million to $338 million, as users withdrew from pools that resembled the exploited ones even where they weren't directly affected. Venus Protocol paused BAL borrowing on Ethereum and set loan-to-value ratios to zero as a precaution.

Chain-level responses diverged sharply along philosophical lines. Berachain halted its network entirely and hard-forked to undo the theft. Polygon relied on validator-level transaction censorship. Sonic Labs shipped a freeze mechanism mid-attack. Gnosis cut off outbound bridging. Haseeb Qureshi of Dragonfly commented that smaller ecosystems should prioritize user safety over strict adherence to "code is law."

15Assessment

The exploit required no reentrancy, no flash-loan trickery in the traditional sense, and no external leverage — only valid, approved contract calls executed by someone who understood Balancer's math more precisely than its own engineering and audit history had. Certora's 2022 work proved solvency at a high level; it did not test roundtrip invariants at the boundaries. Trail of Bits flagged the same rounding pattern in 2021 but could not prove it exploitable at the time and rated it accordingly. Four years later, an attacker proved it decisively, at a cost of $128 million spread across nine networks, dozens of pools, and 27 vulnerable forks — several of which required their host chains to intervene at the validator level, hard-fork, or freeze balances outside of any code path, in order to limit the damage.

BalancerRate Manipulation
Investigation alerts

Get new scam files the moment we publish them — usually 2–3 emails a week.

Enter a valid email address.

No spam, unsubscribe anytime. We never sell your data. Crypto assets are volatile and high-risk; nothing here is financial advice.

You're on the list. Watch your inbox for the next scam file.