
Date: September 9, 2026 (block 120,873,720)
Chain: BNB Chain
Loss: about 2,984,557 BTX, roughly $77.5K, drained out of two vesting contracts; the attacker netted about 63,704 USDT after costs
Class: spot-price oracle manipulation through PancakeSwap V3 slot0, with a slippage check built from the same price
The attacker put 12,000 USDT into BeatSwap's vesting contracts, 10,000 into one and 2,000 into the other, and in return those contracts committed about 3.07 million of their own BTX tokens to liquidity positions priced at a moment when BTX looked almost worthless. A few swaps later, the attacker had walked away with about 2.98 million BTX, which it sold for roughly 77,512 USDT.
That happened in a single transaction on BNB Chain on September 9, 2026. The vesting contracts lost about $77.5K worth of BTX, and the attacker kept about 63,704 USDT of it after paying for the round trip. It was possible because BeatSwap's LiquidityVestingConvert contracts priced BTX from the live state of a PancakeSwap V3 pool, a number anyone with enough borrowed tokens can move for the length of one transaction.
BeatSwap is an IP rights and real-world-asset protocol with BTX as its native token. Its LiquidityVestingConvert contract, along with a second contract called LiquidityVestingConvertOnce that runs the same logic, let anyone call deposit() with USDT. According to the DeFiHackLabs proof of concept, which was checked against BeatSwap's verified source, each deposit sent 75% of the USDT to a treasury and paired the remaining 25% with BTX from the contract's own reserves, then minted a PancakeSwap V3 liquidity position owned by the vesting contract.
To decide how much BTX belonged in that position, the contract needed a price for BTX in USDT. It read one straight from the USDT/BTX pool.
Every Uniswap V3 style pool, PancakeSwap V3 included, keeps its live state in a storage slot called slot0, which holds the current price as sqrtPriceX96 and the current tick. Those values change the instant any swap clears, so they describe the last trade rather than a market average. A TWAP, a time-weighted average price, smooths that out over minutes or hours, which makes it expensive to move in one block.
BeatSwap's contract used slot0 with no TWAP and no deviation check. DeFiHackLabs shows _calculateQuote squaring sqrtPriceX96 to turn the USDT deposit into a BTX amount, and _executeMint reading slot0 again for the current tick and building a range of 6,000 ticks either side of it. The BTX side of the quote was sized from the full deposit, so even a small USDT deposit could pull a large share of the reserve into a badly priced position.
There was a slippage guard, amount1Min, set at 97% of the quote, and it compared the mint against that same manipulated quote, so it couldn't catch the distortion. A bouncer who checks your ID against a photo you handed him a minute earlier will wave everyone through.
For builders, the lesson is that a price a caller can move inside the same transaction is a parameter that caller controls, and any check derived from it inherits the same weakness. Prices that size reserves need a reference the caller can't shift in one block.
The attack ran in transaction 0xcc71...5799 at block 120,873,720, sent from a contract whose constructor executed the whole sequence. DeFiHackLabs lays out the order. The attacker took a 15,950 USDT flash loan from Moolah, then entered a Pancake Infinity Vault lock and flash-borrowed 6,000,000 BTX from the Vault. A flash loan lends tokens with no collateral on the condition that they come back before the transaction ends.
It sold BTX into the V3 pool to push the price down and called deposit() with 10,000 USDT on the first vesting contract, which committed about 1.24 million BTX from its reserve. It sold more BTX, then called deposit() with 2,000 USDT on the second contract, which committed about 1.83 million BTX. Both positions sat around a tick the attacker had chosen by moving the pool.
The attacker then reversed the swap by buying BTX back with USDT, which restored the pool's price and let it recover more BTX than it had put in. It repaid the 6 million BTX to the Vault, sold 82,500 BTX on a second pool, and sold the remaining roughly 2.98 million BTX into an unmanipulated Pancake Infinity pool for about 77,512 USDT. After repaying Moolah and absorbing the 75% treasury share of both deposits, it kept about 63,704 USDT.
Early reports from PANews, KuCoin and Coinfomania, which credited a SlowMist alert, put the loss at about $77,500, which matches the dollar value of the 2,984,557 BTX that left the vesting reserves. That's what the vesting contracts lost, and it's the figure this post uses. The 63,704 USDT figure is the attacker's net after the round trip and the treasury deposits.
Olympix reads a contract the way an attacker does, as states, transitions and entry points, and it takes in the context around the code, here a vesting contract that holds its own BTX and quotes against a live PancakeSwap V3 pool. The state that matters is the vesting reserve, and deposit() is a public transition that moves it based on a price from outside the contract. The engine maps every path through deposit() and narrows them to the feasible ones that can touch the reserve.
Olympix's static analysis surfaces the signal: a value-moving function that reads slot0 sqrtPriceX96 or the current tick as its only price, with no TWAP or deviation bound, and a minimum-output check derived from that same read. Olympix has flagged slot0 price manipulation before in other codebases.
BugPoCer takes it from there by asking what the vesting reserve is supposed to guarantee, then trying every reachable sequence of swaps and deposits against that guarantee, which is what Counterexample-Guided Invariant Refutation means in practice. The invariant for these contracts is that a deposit must never commit more BTX from the reserve than the USDT it brings in is worth at a fair market price. A swap that moves the pool followed by deposit() breaks it immediately, and amount1Min passes because it checks against the moved price.
The result is a counterexample: a large swap into the pool, a deposit at the distorted tick, and a reverse swap that pulls the reserve's BTX out, with the minimal conditions that trigger it and a generated Forge test that replays it. That's the BeatSwap attack produced in development, and because the engine runs at every merge and before release, it surfaces as soon as a contract starts pricing from slot0.
BeatSwap's vesting contracts priced one of their own reserves from a number that any caller with a flash loan could set, and then checked the result against that same number. A rule that a deposit can't commit more reserve than it pays for is something a tool can infer and test on every change to a pricing path. If your contracts quote against a concentrated-liquidity pool and you'd like to see which deposits a counterexample can turn against you, book a technical walkthrough.
Protocol: BeatSwap (BeatXswap)
Chain: BNB Chain
Date: September 9, 2026, 11:54:23 UTC (block 120,873,720)
Loss: about 2,984,557 BTX (about 77,512 USDT) drained from the vesting reserves; about 63,704 USDT attacker net profit
Attacker EOA: 0x67B2...C2a1
Exploit contract: 0xaff5...2DEd
Victim 1 (LiquidityVestingConvert): 0x1e64...bf5D
Victim 2 (LiquidityVestingConvertOnce): 0x9a7A...716F
PancakeSwap V3 USDT/BTX pool (slot0 source): 0xA5Db...a96D
BTX token: 0xAa24...AaA3
Exploit tx: 0xcc71...5799
Block: 120,873,720
DeFiHackLabs: BeatXswap_exp.sol proof of concept
Defimon Alerts: BeatSwap exploit alert
PANews: BeatXswap Suffers Price Manipulation Attack, Losing Approximately $77,500