A flash-loan–funded economic exploit that bled the LEAF token contract's own reserves into its PancakeSwap pool, then skimmed the difference as USDT.
Yes — this is a hack.An attacker with zero starting capital extracted ~$1,627 of USDT by abusing LEAF's transfer-triggered fee logic. Not a normal deposit, swap, or protocol operation.
The transaction is a contract deployment (to = null) sent by EOA 0x1ef4…d3ab. The deployed contract borrows USDT via a Moolah flash loan and, inside the loan callback, repeatedly triggers a side effect in the LEAF token's transfer logic. Each trigger moves LEAF out of the token contract's own balance into the LEAF/USDT PancakeSwap pair. The attacker then unwinds the inflated pool position back into USDT, repays the loan, and keeps the surplus.
Net result: the attacker EOA gains 1,628.42 USDT having supplied no capital; the LEAF/USDT pair loses exactly that much USDT; and the LEAF token contract is drained of 2,011.6 LEAF of its held reserves. This is the signature of an economic exploit, not legitimate activity.
Deploy & pre-approve
The tx deploys attacker contract 0xc77D…3F66, which spawns a helper 0x70e3…17f7 and a sub-contract 0xa5e6…98d4, then grants unlimited USDT/LEAF approvals to the PancakeSwap router and the Moolah lender.
Flash-loan 26,200 USDT from Moolah
rescue(26200e18, 12600e18, 200) → flashLoan(USDT, 26,200) on the Moolah proxy. Execution enters the onMoolahFlashLoan callback with the borrowed USDT in hand.
Seed the pool: swap + add liquidity
Sends 12,600 USDT into the LEAF/USDT pair, swaps for ~10,238 LEAF, then addLiquidity of ~13,600 USDT + ~10,136 LEAF — establishing an LP position it controls.
200× zero-value transfers — the exploit
Fires transferFrom(pair, helper, 0) on LEAF 200 times (the 200 arg to rescue). A transfer from the pair routes into _handleBuy → _distributeBonus(), which fires regardless of amount and flushes a fixed MIN_FEE_POOL (~10 LEAF) tranche of the contract's own balance to LDX bonus recipients — the pool chief among them. ~200 × 10 ≈ 2,011 LEAF, all for free.
Unwind & convert to USDT
Removes liquidity (burn), sweeps the sub-contract, then swapExactTokensForTokensSupportingFeeOnTransferTokens dumps ~11,713 LEAF back into the now–LEAF-rich pair for USDT.
Repay loan, pocket the difference
Repays the 26,200 USDT to Moolah and transfers the 1,628.42 USDT surplus to the attacker EOA.
| Address | Role | Asset | Net Δ |
|---|---|---|---|
| 0x1ef4…d3ab | attacker EOA | USDT | +1,628.42 (+$1,627) |
| 0xa4d6…3d08 | LEAF/USDT pair | USDT | −1,628.42 (−$1,627) |
| 0xa4d6…3d08 | LEAF/USDT pair | LEAF | +1,475.53 |
| 0x386b…0b01 | LEAF token (victim) | LEAF | −2,011.60 |
| 0x0000…dead | burn | LEAF | +203.74 |
| 0xc2d5…850b | LEAF fee wallet | LEAF | +332.34 |
The 2,011.60 LEAF lost by the token contract lands as +1,475.53 (pair) + 203.74 (burn) + 332.34 (fee wallet) — the fee/burn split its own transfer logic applies. USD is current CoinGecko spot, approximate for a historical block.
require(amount > 0) guard on the bonus payoutConfirmed against the verified source (LEAFToken, solc 0.8.34). _transfer has no early-out for amount == 0; its only check is balanceOf(from) >= amount, which 0 >= 0 passes. When the sender is the LP pair, control reaches _handleBuy, which calls _distributeBonus() before touching amount. That function flushes one fixed MIN_FEE_POOL (~10 LEAF) tranche of the contract's own balance to registered LDX bonus recipients on every call. With no zero-amount guard anywhere, transferFrom(pair, …, 0) triggers this payout for free, unbounded — draining the fee pool one tranche at a time.
This belongs to a well-documented family of BSC incidents — fee / burn "skim" attacks funded by Moolah flash loans (see references).
// LEAFToken (verified, solc 0.8.34) — the unguarded side effect function _handleBuy(address from, address to, uint256 amount) internal { _distributeBonus(); // fires even when amount == 0 uint256 burnAmount = amount / 100; // 0 when amount == 0 uint256 finalAmount = amount * 99 / 100; ... } function _distributeBonus() internal { if (feePool < MIN_FEE_POOL) return; // ~10 LEAF per call... uint256 share = minLpAmount[user] * MIN_FEE_POOL / totalStaked; feePool -= share; super._transfer(address(this), user, share); // contract's OWN LEAF out } // attacker loop: 200 × transferFrom(pair, helper, 0) → ~2,011 LEAF drained
| Address | Role | Notes |
|---|---|---|
| 0x1ef40356631d8449dadf4e2fac6389b5d7e7d3ab | attacker EOA | Deployer & profit recipient |
| 0xc77D9d6FBF52a8503Bf6Df3A904d27f478533F66 | attack contract | Deployed by this tx |
| 0x70e35ac23345039a68a184e2f7f6249d7a2217f7 | helper | Runs rescue / flash-loan callback |
| 0x386bf5d829a8e24311120bebec1d7aec32930b01 | LEAF token | Victim — vulnerable transfer logic |
| 0xa4d604e6f888e4796e086a9762af9ff412a83d08 | LEAF/USDT pair | PancakeSwap V2 pool drained of USDT |
| 0x8f73b65b4caaf64fba2af91cc5d4a2a1318e5d8c | Moolah lender | Flash-loan source (26,200 USDT) |
| 0x55d398326f99059ff775485246999027b3197955 | USDT (BSC) | Borrowed & stolen asset |
| 0x10ed43c718714eb63d5aa57b78b54704e256024e | PancakeSwap router | Swaps & liquidity ops |
Prepared with the Dedaub EVM transaction triager. Trace via debug_traceTransaction (callTracer); value flows are complete and independent of trace expansion.
USD figures are current CoinGecko spot and approximate for a historical block. No public incident report was found for this specific tx at time of writing — the classification rests on the on-chain evidence above.