0xa245deda8553c6e4c575baff9b50ef35abf4c8f990f8f36897696f896f240e3a0xe68c1d72340aeefe5be76eda63ae2f4bc7514110EthereumIn Ethereum mainnet block 20240539, attacker EOA 0xfde0d1575ed8e06fbf36256bcdfa1f359281455a sent transaction 0xa245deda8553c6e4c575baff9b50ef35abf4c8f990f8f36897696f896f240e3a to attacker contract 0x6980a47bee930a4584b09ee79ebe46484fbdbdd0, which drained DeFiPlaza at 0xe68c1d72340aeefe5be76eda63ae2f4bc7514110. The attack first minted a large LP position with addMultiple(), then burned that LP for ETH with removeLiquidity(), reducing the pool ETH reserve from 4546186764390328408 wei to 1, and then used 1-unit swaps to drain the full opposite-side reserves token by token.
The root cause is a victim-side logic failure inside DeFiPlaza. removeLiquidity() allows a listed reserve to be withdrawn down to zero or near-zero, and swap() then prices against that zero input reserve without rejecting the trade. Once initialInputBalance becomes zero, the swap denominator collapses and the output amount becomes the full output reserve.
DeFiPlaza is a multi-asset DEX whose swap pricing uses a local x*y=k-style formula over the current input and output balances. ETH is represented by the zero address, and the contract is designed to support both single-sided liquidity operations and pairwise swaps across its listed assets.
Two code paths matter for this incident. lets a user mint LP by depositing the full listed-token basket in proportion to pool balances. then lets that LP be redeemed single-sided into one selected asset. Because the subsequent calculation assumes a strictly positive input-side reserve, reserve safety depends on single-sided withdrawal never leaving a tradable market with a zero reserve.
addMultiple()removeLiquidity()swap()The attack used Aave/Balancer and other venues only as transient funding or cleanup paths. The safety failure that made theft possible occurred entirely inside DeFiPlaza’s own reserve accounting and swap pricing.
The vulnerability class is a direct protocol attack caused by invalid reserve-domain handling in the victim DEX. DeFiPlaza’s verified source shows that ETH-input swaps derive initialInputBalance as address(this).balance - inputAmount, and compute the output as:
uint256 netInputAmount = inputAmount * _config.oneMinusTradingFee;
outputAmount = netInputAmount * initialOutputBalance / ((initialInputBalance << 64) + netInputAmount);
The same verified source shows that single-sided withdrawal computes the payout as:
F_ = (1 << 64) - (LPamount << 64) / totalSupply();
F_ = F_ * F_;
F_ = F_ * F_ >> 192;
F_ = F_ * F_;
F_ = F_ * F_ >> 192;
actualOutput = initialBalance * ((1 << 64) - F_) >> 64;
There is no postcondition ensuring the remaining reserve stays positive after removeLiquidity(). In the seed transaction, the attacker minted 232672546280000190645164 LP, withdrew almost the full ETH side, and left the pool with 1 wei of ETH. The next ETH-to-SPELL swap therefore observed initialInputBalance == 0, making the denominator equal to netInputAmount and the output equal to the entire SPELL reserve. The same pattern then propagated from SPELL to YFI and onward across the remaining listed assets.
The exploit transaction is fully visible in the seed trace. The key sequence is:
0x6980...bdd0::yoink()
DeFiPlaza::addMultiple{value: 32732544703610364537600}(...)
DeFiPlaza::removeLiquidity(232672546280000190645164, 0x0000000000000000000000000000000000000000, 0)
DeFiPlaza::swap{value: 1}(0x0000000000000000000000000000000000000000, 0x090185f2135308BaD17527004364eBcC2D37e5F6, 1, 0)
DeFiPlaza::swap(0x090185f2135308BaD17527004364eBcC2D37e5F6, 0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e, 1, 0)
The balance-diff artifact confirms that the ETH reserve was effectively zeroed:
{
"address": "0xe68c1d72340aeefe5be76eda63ae2f4bc7514110",
"before_wei": "4546186764390328408",
"after_wei": "1",
"delta_wei": "-4546186764390328407"
}
Once the reserve was reduced to 1, the swap path became unsafe. For the ETH-input SPELL swap, the contract computes initialInputBalance = address(this).balance - inputAmount. Under the exploit path, that value becomes zero, so:
outputAmount = netInputAmount * initialOutputBalance / ((0 << 64) + netInputAmount)
= initialOutputBalance
The trace shows the exact exploit effect:
emit Swapped(
sender: 0x6980...bdd0,
inputToken: 0x0000000000000000000000000000000000000000,
outputToken: 0x090185f2135308BaD17527004364eBcC2D37e5F6,
inputAmount: 1,
outputAmount: 23380964939429314970150052
)
emit Swapped(
sender: 0x6980...bdd0,
inputToken: 0x090185f2135308BaD17527004364eBcC2D37e5F6,
outputToken: 0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e,
inputAmount: 1,
outputAmount: 2211784511312059935
)
The balance diff independently confirms the drain outcome. DeFiPlaza’s SPELL balance moved from 24541399146686254066632302 to 1, and its YFI balance moved from 2321558868899811100 to 1. This is the invariant break in concrete terms: a tradable DeFiPlaza market remained open after one side of the reserve pair had been reduced to zero, and the pricing formula then paid out the full opposite reserve.
The adversary flow was a single normal mainnet transaction submitted by EOA 0xfde0d1575ed8e06fbf36256bcdfa1f359281455a. The transaction called attacker contract 0x6980a47bee930a4584b09ee79ebe46484fbdbdd0, whose selector 0x9846cd9e resolves to yoink().
The attacker contract sourced temporary liquidity, then called DeFiPlaza::addMultiple with ETH plus the listed ERC-20 basket to mint a dominant LP position. Immediately afterward it called DeFiPlaza::removeLiquidity(..., address(0), 0) to redeem that LP into ETH only, which left the pool’s ETH side effectively empty.
With the ETH side zeroed, the attacker executed a chain of minimal-input swaps. The first 1 wei ETH swap drained the full SPELL reserve. The next 1 SPELL swap drained the full YFI reserve. The same pattern then continued across WBTC, DFPgov, CVX, LINK, eXRD, DAI, SUSHI, MATIC, MKR, USDC, COMP, CRV, and USDT, as shown by the successive emit Swapped lines in the trace.
The balance-diff artifact shows that attacker-related address 0xc70f00cd7e461686b04b0e912e309beca8b80ea0 received extracted proceeds such as 13409070847 USDC and 257253140376036772912842 DFPgov during the transaction. The attacker contract’s own native ETH balance changed from 153690784263720923028 to 135562280214465500516, a delta of -18128504049255422512, while the exploit still realized the non-monetary success condition of zeroing the reserve and draining the paired markets.
The victim lost essentially the full reserves of multiple listed assets in one transaction. The measured losses from the seed balance-diff artifact are:
4546186764390328407 wei13409070847641835086647538184501875484747552145288499561921216758027380073383255836149431724488770365397245413991466862540666323012321558868899811099The impact is direct theft from DeFiPlaza, not a governance compromise, oracle failure, or privileged misuse. Any unprivileged actor able to replicate the reserve-zeroing state transition could realize the same swap-domain failure.
0xa245deda8553c6e4c575baff9b50ef35abf4c8f990f8f36897696f896f240e3a/workspace/session/artifacts/collector/seed/1/0xa245deda8553c6e4c575baff9b50ef35abf4c8f990f8f36897696f896f240e3a/metadata.json/workspace/session/artifacts/collector/seed/1/0xa245deda8553c6e4c575baff9b50ef35abf4c8f990f8f36897696f896f240e3a/trace.cast.log/workspace/session/artifacts/collector/seed/1/0xa245deda8553c6e4c575baff9b50ef35abf4c8f990f8f36897696f896f240e3a/balance_diff.json0xe68c1d72340aeefe5be76eda63ae2f4bc7514110