Calculated from recorded token losses using historical USD prices at the incident time.
0x85ac5d15f16d49ae08f90ab0e554ebfcb145712342c5b7704e305d602146d4520xcdb189d377ac1cf9d7b1d1a988f2025b99999999BSC0xca23e8d408d769661cb480a3fd45d6be370c45f7BSCBCE was exploited in BNB Chain transaction 0x85ac5d15f16d49ae08f90ab0e554ebfcb145712342c5b7704e305d602146d452 at block 88215293. The attacker used public Venus liquidity to accumulate BCE, deliberately set BCE's deferred scheduledDestruction state with a sell into the BCE/USDT Pancake pair, then triggered that deferred destruction with an ordinary non-pair BCE transfer. BCE burned tokens directly from the pair and immediately called sync(), collapsing the pair's BCE reserve to 10000 while leaving USDT in place long enough for the attacker to dump BCE back into the distorted pool and drain USDT.
BCE routes transfer logic through _update, so ordinary transfers, buys, sells, fee handling, and pair-side burns all share the same hook. The vulnerable market was the public BCE/USDT Pancake pair at 0xca23e8d408d769661cb480a3fd45d6be370c45f7, which served as the price source used by the exploit path. The attacker also used Venus flash liquidity and Venus core-pool borrowing, but those public financing steps only amplified capital; they did not create the vulnerability.
The root cause is a transfer-hook design error in BCE. On sells into the pair, BCE computes a reserve-dependent per value and accumulates scheduledDestruction. That deferred destruction amount is not bound to the seller that created it and is not limited to later pair-controlled flows. On any later non-pair transfer by a non-whitelisted address, BCE executes super._update(_uniswapV2Pair, address(0), scheduledDestruction) and immediately calls . This violates the invariant that ordinary token transfers must not arbitrarily change AMM reserves outside the pair’s own swap, mint, or burn paths. Once the pair is synchronized with nearly no BCE left, the constant-product price becomes unusably distorted and the attacker can extract the pair’s USDT liquidity with a final BCE sale.
IUniswapV2Pair(_uniswapV2Pair).sync()The critical victim logic appears in BCE _update:
// BCE sell path
uint256 per = reserveBCE / 2100000 ether;
per = per >= 10 ? 10 : per;
scheduledDestruction += (value * per * 10) / 100;
// Later non-pair transfer path
if (scheduledDestruction > 0) {
super._update(_uniswapV2Pair, address(0), scheduledDestruction);
IUniswapV2Pair(_uniswapV2Pair).sync();
scheduledDestruction = 0;
}
In the seed transaction, the attacker first financed the operation through Venus flash loans, collateralized positions, and borrowing, then bought BCE out of the pair and performed a sell to populate scheduledDestruction. The collected trace shows the exploit helper later performing the trigger transfer that causes BCE to burn pair-held BCE and synchronize reserves. At that trigger point, the trace shows the pair-side BCE balance storage slot for the pair move to 10000, and the pair reserve view immediately afterward returns reserve0 = 36575519358323350250416289 USDT and reserve1 = 10000 BCE. Only after that reserve collapse does the attacker execute the final BCE sale into the pool and receive almost all remaining USDT. The collected balance diff confirms the BCE/USDT pair lost 800009324167400507778023 USDT in the transaction.
The exploit was a single transaction and fully permissionless. The sender EOA 0x9f7eabd7c3538ba6b9d10eede63712c0ecce6d69 called attack contract 0xaf7f22831d1ec86d24be51a1760b04ad4b58e9eb, which in turn deployed helper contract 0xb68419184079c7a69a9a7decb53b691b30d5eb54. The trace shows three stages:
scheduledDestruction.sync(), followed by a final BCE sale that drains USDT, loan repayment, and profit distribution.Representative trigger-and-drain evidence from the seed trace:
PancakePair::getReserves() -> 36575519358323350250416289 USDT, 10000 BCE
BCE::balanceOf(pair) -> 1412962214473276250006675
PancakePair::swap(36575519358323350250156783, 0, attacker, 0x)
emit Transfer(from: PancakePair, to: attacker, amount: 36575519358323350250156783)
emit Sync(reserve0: 259506, reserve1: 1412962214473276250006675)
The attacker cluster also received final payouts in both native BNB and USDT. The balance diff shows 0x4848489f0b2bedd788c696e2d79b6b69d7484848 gained 189803280299736520697 wei and the transaction sender EOA gained 680007925542290431611320 USDT.
The direct measurable loss was the BCE/USDT Pancake pair’s USDT liquidity. The pair balance diff moved from 800009324167400508037529 to 259506, for a net loss of 800009324167400507778023 USDT base units. The pair’s BCE side was also force-collapsed to dust during the trigger stage, creating the artificial price that enabled the drain. The affected public components were the BCE token contract and the BCE/USDT Pancake pair.
0x85ac5d15f16d49ae08f90ab0e554ebfcb145712342c5b7704e305d602146d4520xcdb189d377ac1cf9d7b1d1a988f2025b999999990xca23e8d408d769661cb480a3fd45d6be370c45f7_update logic