Calculated from recorded token losses using historical USD prices at the incident time.
0xc748673057861a797275cd8a068abb95a902e8deBSC0x0536c8b0c3685b6e3c62a7b5c4e8b83f938f12d1BSC0xc736ca3d9b1e90af4230bd8f9626528b3d4e0ee0BSCOn BSC, an unprivileged adversary executed a three-transaction sequence around blocks 29033192, 29033590, and 29295011 to harvest a deterministic cross-pool spread in CoinToken. The attacker first primed a public strategy contract with Treat-LP liquidity and Venus market access, then topped it up with 0.001 BNB, and finally used a public Pancake V3 flash loan plus standard Venus borrowing to force CoinToken's public swapAndLiquify branch on Pancake while Treat-LP remained temporarily mispriced.
The root cause was not a bug in Venus. CoinToken hard-wired its protocol-owned liquidation path to the Pancake router and Pancake pair, but the token also traded on Treat-LP. Once CoinToken inventory inside the token contract approached numTokensSellToAddToLiquidity, any non-Pancake-pair transfer could publicly trigger a Pancake-only market sale and liquidity add. That gave any searcher with sufficient public capital a deterministic way to manufacture a spread between Treat-LP and Pancake, then arbitrage it. Based on the collected evidence, the three-transaction sequence realized at least 441.848474237884914737 BNB of cash profit after gas, with residual Treat-LP and CoinToken value still left on the strategy contract.
CoinToken (0xc748673057861a797275cd8a068abb95a902e8de) is a fee-on-transfer token. Each taxed transfer accumulates a liquidity fee in address(this), and the contract later sells that inventory through swapAndLiquify.
The crucial design choice is that CoinToken binds to a single Pancake router and a single Pancake WBNB pair created at deployment. That means protocol-owned inventory accumulated from any venue is always liquidated on Pancake.
0xbaf3e4841614eca5480c63662b41cd058ee5c85dc69198b29e7ab63b84bc866cswapAndLiquifyAt the same time, CoinToken also traded on Treat-LP (0x0536c8b0c3685b6e3c62a7b5c4e8b83f938f12d1) in addition to the Pancake pair (0xc736ca3d9b1e90af4230bd8f9626528b3d4e0ee0). A trader who can predict when swapAndLiquify will fire can buy on one venue, force the contract to sell on the other venue, then immediately arbitrage the spread back.
The attacker also relied on the verified AddRemoveLiquidity helper at 0x9869674e80d632f93c338bd398408273d20a6c8e. That helper removes LP into itself and forwards the received tokens to an arbitrary caller-specified to address, which makes it useful for precisely positioning CoinToken and WBNB balances during the threshold-trigger sequence.
Venus only supplied temporary public leverage. The attacker used public enterMarkets, mint, borrow, repayBorrow, and redeemUnderlying flows to amplify capital inside the final transaction, but the economic opportunity existed because CoinToken exposed a public, deterministic Pancake-only sale while a second live market existed elsewhere.
This incident is a MEV-style ACT opportunity, not a traditional contract exploit such as reentrancy or broken authorization. CoinToken exposes a publicly triggerable branch in _transfer that checks whether the token contract's own inventory has reached numTokensSellToAddToLiquidity. If the inventory is high enough and the sender is not the Pancake pair, the contract executes swapAndLiquify before processing the caller's transfer.
That branch is economically dangerous because CoinToken traded on multiple venues but only liquidated its inventory on Pancake. The attacker could therefore push the token contract's inventory just below the threshold on Treat-LP, choose the next transfer that crosses and triggers the branch, and cause a large protocol-owned market order to hit Pancake without the Treat-LP price moving in sync. The attacker then bought back on the newly distorted Pancake curve and sold the enlarged CoinToken position back into Treat-LP.
The safety invariant that failed is economic rather than arithmetic: a public user transfer should not allow any arbitrary trader to deterministically force a protocol-owned market order on one venue while leaving another active venue temporarily unadjusted. The concrete code-level breakpoint is the CoinToken _transfer threshold branch:
uint256 contractTokenBalance = balanceOf(address(this));
bool overMinTokenBalance = contractTokenBalance >= numTokensSellToAddToLiquidity;
if (
overMinTokenBalance &&
!inSwapAndLiquify &&
from != uniswapV2Pair &&
swapAndLiquifyEnabled
) {
contractTokenBalance = numTokensSellToAddToLiquidity;
swapAndLiquify(contractTokenBalance);
}
At block 29295010, the token contract already held 202648391392823466814133 raw CoinToken against a threshold of 210000000000000000000000, so only 7351608607176533185867 more raw units were needed before the next non-Pancake-pair transfer would trigger the Pancake-only liquidation. That state was publicly observable and therefore schedulable by any capable searcher.
The exploit depended on four public conditions being true at the same time:
address(this).numTokensSellToAddToLiquidity.The attacker satisfied the capital requirement using public Pancake V3 flash liquidity plus Venus collateralized borrowing. The actual vulnerable mechanism, however, was entirely inside CoinToken. The collected source shows that CoinToken stores _taxFee, _liquidityFee, uniswapV2Pair, and numTokensSellToAddToLiquidity in its constructor and never generalizes swapAndLiquify to other venues. When the threshold branch fires, swapTokensForEth sells half of the inventory into Pancake and addLiquidityETH adds the other half back to Pancake on behalf of owner 0x505d1180061727c59ce04e7acfc117283cf797f0.
The seed transaction trace shows the decisive exploit sequence:
0x4f3126d5DE26413AbDCF6948943FB9D0847d9818::flash(...)
VBNB::borrow(99462970435884484705580)
0x9869674E80D632F93c338bd398408273D20a6C8e::removeLiquidity(..., CoinToken, ...)
0x9869674E80D632F93c338bd398408273D20a6C8e::removeLiquidity(..., PancakePair, ...)
PancakeRouter::swapExactTokensForETHSupportingFeeOnTransferTokens(105000000000000000000000, ...)
PancakeRouter::addLiquidityETH{value: 184058984163680973240}(...)
0x9869674E80D632F93c338bd398408273D20a6C8e::removeLiquidity(..., BabyDogePair, ...)
VBNB::repayBorrow{value: 99462970435884484705580}()
VBep20Delegator::redeemUnderlying(18528322083519255027845748)
VBep20Delegator::redeemUnderlying(11891269826866403367786530)
WBNB::transfer(0xEE6764Ac7aa45eD52482e4320906FD75615bA1d1, 441905957368884914737)
That trace matches the economic story exactly. The attacker used Treat-LP trading and helper-mediated liquidity removals to arm the threshold, triggered CoinToken's public Pancake sale, then harvested the new cross-pool spread before unwinding every temporary debt. The flash loan and Venus liabilities were completely repaid, which confirms this was not an under-collateralization bug in the lending leg.
The vulnerable components are:
_transfer threshold logic.swapAndLiquify, swapTokensForEth, and addLiquidity.removeLiquidity.The violated security principles are straightforward:
The adversary cluster consisted of EOA 0xee6764ac7aa45ed52482e4320906fd75615ba1d1 and strategy contract 0x9a6b926281b0c7bc4f775e81f42b13eda9c1c98e.
setup() priming transaction: 0xd8d0da7e107d72bc3b2d998277a36397cc72f43d0751218d03664539c90782ed at block 29033192.0x9A6b926281B0C7bC4f775E81F42b13eDA9C1C98E::setup{value: 10000000000000000}()
Comptroller::enterMarkets([vWBNB, vUSDT, vBUSD])
BabyDogeRouter::swapExactETHForTokensSupportingFeeOnTransferTokens{value: 5000000000000000}(... CoinToken ...)
AddRemoveLiquidityForFeeOnTransferTokens::addLiquidity(CoinToken, WBNB, 773165306464788510, 5000000000000000, ...)
emit LiquidityAdded(... lpAmount: 57696715643381948)
This priming call entered Venus markets, bought CoinToken on Treat-LP, added Treat-LP liquidity through the helper, minted 57,696,715,643,381,948 LP tokens to the strategy contract, and left it with 0.001 BNB plus 500057464032669 wei of WBNB residue.
0x65e38151a1a37129c76ed5a84c3adbc8a0bc5e443cf4454c836931420d73c56a at block 29033590.0x9A6b926281B0C7bC4f775E81F42b13eDA9C1C98E::execute{value: 1000000000000000}(0xEE6764Ac7aa45eD52482e4320906FD75615bA1d1, 0x3a4b66f1)
0xEE6764Ac7aa45eD52482e4320906FD75615bA1d1::stake()
This second transaction only refreshed the strategy contract's native balance. No ERC-20 deltas changed, but the extra 0.001 BNB became part of the capital later consumed in the exploit leg.
0xbaf3e4841614eca5480c63662b41cd058ee5c85dc69198b29e7ab63b84bc866c at block 29295011.The strategy called into the Pancake V3 pool, borrowed USDT and BUSD, minted vUSDT and vBUSD, borrowed 99,462.970435884484705580 BNB from Venus, and used the pre-seeded helper and LP state to push CoinToken inventory over the public threshold. Once the attacker chose the trigger transfer, CoinToken executed swapAndLiquify on Pancake. The attacker then bought back on Pancake, sold into Treat-LP, repaid VBNB, redeemed the vUSDT and vBUSD collateral, bought exact stablecoin amounts for flash fees, and repaid the Pancake V3 pool.
At the end of the seed transaction, the strategy contract transferred exactly 441905957368884914737 wei of WBNB to controller EOA 0xee6764ac7aa45ed52482e4320906fd75615ba1d1. Combined with the initial 0.011 BNB principal and 0.046483131 BNB of sequence gas, that yields a conservative realized-cash delta of 441.848474237884914737 BNB. This figure is conservative because the strategy contract still retained 57,696,712,643,381,948 Treat-LP and 9,014,733,915,716 raw CoinToken after the seed transaction.
The measurable realized-cash impact is at least:
BNB: 441848474237884914737 raw wei, decimal = 18The economic loss came from cross-pool mispricing between Treat-LP and Pancake after CoinToken's forced Pancake-only liquidation. The attacker did not need privileged access, private order flow, or protocol admin rights. Every leg used public contracts and publicly observable state, which is why the incident qualifies as an ACT-style MEV realization.
0xbaf3e4841614eca5480c63662b41cd058ee5c85dc69198b29e7ab63b84bc866c/workspace/session/artifacts/collector/seed/56/0xbaf3e4841614eca5480c63662b41cd058ee5c85dc69198b29e7ab63b84bc866c/trace.cast.log/workspace/session/artifacts/collector/seed/56/0xbaf3e4841614eca5480c63662b41cd058ee5c85dc69198b29e7ab63b84bc866c/balance_diff.json/workspace/session/artifacts/collector/iter_7/tx/56/0xd8d0da7e107d72bc3b2d998277a36397cc72f43d0751218d03664539c90782ed/summary.json/workspace/session/artifacts/collector/iter_7/tx/56/0x65e38151a1a37129c76ed5a84c3adbc8a0bc5e443cf4454c836931420d73c56a/summary.json/workspace/session/artifacts/collector/iter_7/contract/56/0x9a6b926281b0c7bc4f775e81f42b13eda9c1c98e/summary.json/workspace/session/artifacts/collector/seed/56/0xc748673057861a797275cd8a068abb95a902e8de/src/Contract.solhttps://bscscan.com/address/0x9869674e80d632f93c338bd398408273d20a6c8e#codehttps://bscscan.com/address/0xfe872ddeae0a53486c25ed882786d592e302d80c#code