All vulnerabilities
CRITICALWeb3exploited in the wild

WEB3-SPARTAN-2021

Web3 · BNB Chain · Spartan Protocol

Summary

On 1 May 2021 Spartan Protocol on BNB Chain lost about $30 million from its V1 liquidity pools via a flash-loan-amplified accounting attack. On removeLiquidity, calcLiquidityShare() computed each holder's payout as _amount * units / totalSupply, where _amount was the token's live balanceOf(pool) rather than the pool's recorded reserves. Unlike Uniswap V2, the pool's internal balance bookkeeping only reduced the stored baseAmount/tokenAmount and never re-synced to actual balances. The attacker added liquidity, then transferred extra tokens directly into the pool to inflate balanceOf, then burned LP units; the share formula read the inflated live balance and paid out far more than was deposited. This is an incorrect liquidity-share accounting bug using a manipulable balance instead of cached reserves.

How to avoid it in your code

  • Compute LP-share payouts from cached/synced reserves, never from live balanceOf(address(this)) which anyone can inflate
  • Mirror Uniswap V2's _update() pattern: re-sync recorded reserves to balances atomically and use only the recorded value
  • Detect donated/unsolicited tokens (balance > reserves) and skim or ignore the surplus rather than crediting it
  • Add flash-loan invariant tests asserting withdrawn assets never exceed deposited share for any single transaction

References

Related vulnerabilities

All Web3 →