BabySwap Reward Theft
Exploit Transactions
Victim Addresses
0x5c9f1a9ced41ccc5dcecda5afc317b72f1e49636BSC0x8317c460c22a9958c27b4b6403b98d2ef4e2ad32BSCLoss Breakdown
Similar Incidents
MultiSender Arbitrary From Theft
34%RewardVault Proxy Reinitialization Theft
34%SellToken Reward Oracle Manipulation
34%QiQi Reward Quote Override Drain
33%Sareon Reward Drain
33%TRUST/FCN Flash-Swap Reward Exploit
32%Root Cause Analysis
BabySwap Reward Theft
1. Incident Overview TL;DR
An unprivileged attacker abused BabySwap's smart-router and swap-mining composition to mint BABY rewards from fabricated swap volume, then sold the mined BABY into the real BABY/USDT pool for profit. The core failure was that BabySmartRouter accepted caller-supplied factory and pair contracts for quote generation, while SwapMining trusted the router-provided amountOut as if it came from a real canonical swap.
2. Key Background
BabySmartRouter extends normal BabySwap routing by accepting a factories array from the caller for route discovery and reserve reads. SwapMining separately rewards swaps by converting the router-reported output amount into target-token quantity using the canonical BabySwap oracle, then tracks that quantity per pool until takerWithdraw() pays BABY rewards. This design only remains safe if the quoted output amount is derived from a real approved pair and reflects actual delivered output.
3. Vulnerability Analysis & Root Cause Summary
The bug is an attack-class trust-boundary failure between routing and reward accounting. In BabyLibrarySmartRouter.sol, pairFor simply calls IBabyFactory(factory).getPair(...) on the caller-supplied factory, and getAggregationAmountsOut uses that result to compute the route output. In BabySmartRouter.sol, _swap forwards that computed amountOut into SwapMining.swap(msg.sender, input, output, amountOut) before the pair swap is executed. In SwapMining.sol, swap maps the token pair back to the canonical BabySwap pair, then values the supplied amountOut through getQuantity and Oracle.sol without verifying canonical execution or actual token delivery. The violated invariant is: SwapMining should only credit quantity for swaps that actually execute on a protocol-approved pair and should value only the real output amount delivered by that canonical swap. The concrete breakpoint is the router passing an untrusted quoted output into SwapMining.swap, followed by SwapMining.getQuantity treating it as genuine trading volume.
// Router: reward accounting trusts caller-selected factories.
amounts = BabyLibrarySmartRouter.getAggregationAmountsOut(factories, fees, amountIn, path);
...
ISwapMining(swapMining).swap(msg.sender, input, output, amountOut);
IBabyPair(BabyLibrarySmartRouter.pairFor(factories[i], input, output)).swap(...);
// Reward system: quantity is priced from the reported output amount.
address pair = BabyLibrary.pairFor(address(factory), input, output);
uint256 quantity = getQuantity(output, amount, targetToken);
user.quantity = user.quantity.add(quantity);
4. Detailed Root Cause Analysis
The attacker first deployed helper contract 0xde7e741bd9dc7209b56f1ef3b663efb288c928d4 from EOA 0x0000000038b8889b6ab9790e20fc16fdc5714922 in tx 0xc82b5cae6a13b4193d2b909d78996a69566de8f85f9cb693baf384c2f86c118b. The creation record in de7e_creation.json shows that this helper embedded BabySwap addresses and the targeted token set. In the seed exploit tx 0xcca7ea9d48e00e7e32e5d005b57ec3cac28bc3ad0181e4ca208832e62aa52efe, the trace shows repeated calls from the helper into fake pair/factory contract 0x6dd035a2bd0daf5ae0a73f2442b3ec05766a8b75, then into BabySmartRouter.
The fake pair answered getPair with itself and getReserves with manipulated reserve ratios such as 1 versus 1e28, causing the router to compute an enormous amountOut. The same seed trace then shows SwapMining::swap(..., 9999000099990000999900009999) and canonical Oracle::consult(...) calls that priced this forged amount using the real BabySwap pool for the token pair. Finally, the fake pair's swap function returned the attacker's input tokens back to the attacker instead of delivering genuine output tokens, so the attacker preserved principal while still accumulating mining quantity.
After enough fake quantity was accumulated, the attacker called SwapMining::takerWithdraw() in the same transaction and received BABY rewards. The attacker then sold BABY through the real BABY/USDT route, which is visible in the trace and confirmed in balance_diff.json: SwapMining lost 2938417232983949790429005 BABY, and attacker contract 0xde7e... gained 65055710342668455930346 raw USDT units.
5. Adversary Flow Analysis
Stage 1 was preparation: the attacker EOA deployed the exploit helper. Stage 2 was fake-volume injection: the helper configured attacker-owned fake pair logic, called BabySmartRouter with attacker-chosen factories, and used fake reserves to induce huge quoted outputs. Stage 3 was reward realization: the helper withdrew BABY from SwapMining and swapped BABY into the real BABY/USDT market.
Representative trace evidence from the seed transaction:
BabySmartRouter::swapExactTokensForTokens(... [0x6dd0...], [0], ...)
SwapMining::swap(..., 9999000099990000999900009999)
Oracle::consult(..., 9999000099990000999900009999, USDT)
0x6dd0...::swap(..., attacker, 0x)
SwapMining::takerWithdraw()
BabyPair::swap(... USDT ..., 0xdE7E...)
This sequence is ACT-compatible because the attacker only needed public chain state, public protocol contracts, and self-deployed helper contracts. No privileged key, governance role, or private settlement path was required.
6. Impact & Losses
The immediate protocol loss was unauthorized BABY reward emission from SwapMining. The attacker converted that BABY into real market value by selling into the canonical BABY/USDT pair. The measured seed-incident profit was 65055710342668455930346 raw USDT units, with only 64733677480807860 wei of BNB spent on gas by the attacker EOA. The loss was therefore economically positive for the attacker and depleted both SwapMining reward inventory and BABY/USDT pool liquidity.
7. References
- Seed exploit tx
0xcca7ea9d48e00e7e32e5d005b57ec3cac28bc3ad0181e4ca208832e62aa52efe - Preparation tx
0xc82b5cae6a13b4193d2b909d78996a69566de8f85f9cb693baf384c2f86c118b - trace.cast.log
- balance_diff.json
- BabyLibrarySmartRouter.sol
- BabySmartRouter.sol
- SwapMining.sol
- Oracle.sol
- de7e_creation.json