On Friday, July 5th, 2024, at 13:15 UTC, the DefiPlaza DEX on Ethereum suffered a devastating attack that drained all user funds. This post-mortem analysis aims to provide a detailed explanation of the exploit, the timeline of events, and the steps the team is taking moving forward. We are committed to full transparency and accountability to our community.
Overview of the Exploit
At block number 20240539 (July 5th, 2024, 13:15:35 UTC), a carefully crafted, complex transaction that exploited a vulnerability in the DefiPlaza V2 smart contract was executed. The transaction successfully drained all tokens from the liquidity pool, impacting all users.
This transaction originated with a bad actor who was, however, careless. When the original attack transaction entered the Ethereum mempool, it was noticed by an MEV bot operated by a third party, Yoink. The MEV bot scouted the highly profitable transaction and front-ran it by paying the Ethereum validators for priority execution.
All damage was done in that single transaction. Despite the best efforts of our team and multiple security firms who alerted us shortly after the incident, it was too late to intervene by pausing the protocol. Unfortunately, all funds in DefiPlaza on Ethereum were lost in the attack.
Detailed Attack Structure
The attack was complex, leveraging flash loans, token swaps, and a vulnerability in the removeLiquidity
function of the contract. Below is a step-by-step breakdown:
- Step 1: Borrow $129.6M worth of various tokens (ETH, USDC, USDT, WBTC, DAI, MKR, CRV) from the Balancer vault using flash loans.
- Step 2: Swap out most of the other 10 tokens listed on DefiPlaza so that the ratios in the exchange are equal to those held by the attacker.
- Step 3: Add all tokens as liquidity to DefiPlaza, making the attacker the dominant liquidity provider (holding >94% of LP tokens).
- Step 4: Withdraw all LP tokens received in Step 3 into a single token (ETH), thereby completely emptying the ETH part of the pool ← This should not have been possible.
- Step 5: Swap 1 wei to drain SPELL.
- Step 6: Swap 10-18 SPELL to drain YFI.
- Step 7-19: Sequentially drain the other listed tokens by sequentially swapping tiny amounts of previously drained tokens.
- Step 20: Repay the initial flash loans.
This highly orchestrated transaction consumed 7.8M gas (block limit is 30M gas total), demonstrating the intricate nature of the attack.
Note: several token swaps were also part of the complete transaction, but for brevity, the list above is restricted to the steps most relevant to the attack vector.
Root Cause: Technical Vulnerability
The vulnerability lies in the removeLiquidity function of the DefiPlaza contract. Specifically, it involved a rounding error when inputting a LPamount
that exceeded 15/16ths of the total LP amount. For sufficiently large input fractions, F_
it will be rounded down to zero at line 322. The result of this rounding error is that all liquidity for this token was removed. Under normal operations, it’s not possible to have zero holdings for any of the tokens, and the contract is not robustified for this situation, leading to an exploitable situation.
This issue is highly unlikely to occur under normal operation, as removing a significant part of liquidity into one token is otherwise a very uneconomical thing to do. However, once the contract is in this state the attacker was able to leverage the zero-liquidity state to remove the liquidity from the other listed tokens one by one in a cleverly constructed ‘domino’ swap sequence.
The attack required significant liquidity to achieve a dominant LP position. This was enabled by the interest-free flash loans that are available in the Ethereum ecosystem.
This attack has always been possible to carry out but was only executed 3 years after deploying, holding significant liquidity across the entire period. Sophisticated actors are likely using newly available tools to scout for vulnerabilities in older contracts.
Timeline of the Attack
- Jul-5th-2024, 13:15:35 UTC: The attacker ( 0x14B362d2E38250604F21A334D71C13E2eD478467) deployed a malicious contract (0xa4E8969BBa1e1d48c30c948de0884Cdff43e2d54).
- The attacker initiated the transaction that would drain DefiPlaza (0xe00b0998d71b0e657379be196babd1637a653c100e8162853ca6616c3970790d).
- An MEV bot, operated by Yoink, front-ran the attacker’s transaction. To do so, Yoink paid a substantial 62.5 ETH bribe to the validator processing the transaction (Lido).
- Yoink successfully captured approximately $24,000 worth of tokens from the transaction but promptly and graciously returned them to the DefiPlaza team within 30 minutes after being contacted (through Blockscan).
- The 62.5 ETH bribe was distributed to all Lido stakers according to their protocol’s MEV capture mechanism.
Immediate Impact
The result of this exploit was catastrophic for DefiPlaza:
• All liquidity on Ethereum was drained, resulting in the total loss of user funds. As mentioned above, approximately 10% of the funds were quickly recovered and are currently held by the team.
• The protocol is no longer operational on Ethereum, and there is currently no plan to restore liquidity on this chain.
• The bridge to Radix was briefly paused to prevent potential further damage but has since been reopened.
Next Steps and Recovery
In response to this attack, we are exploring all available avenues for recovery. Our primary focus is to retrieve any stolen funds distributed through the Lido validator by proposing a DAO governance vote to recover the funds. If successful, any recovered assets will be redistributed to XDP2 token holders.
Final Words
This attack had a massive impact on the DefiPlaza team and is a harsh reminder of the challenges inherent in decentralized finance. We’re devastated by the impact on our community, the project, and ourselves. Although everyone is aware that code audits are no hard guarantee of security, after a successful audit and three years of problem-free operation, we were completely blindsided by this exploit.
We will continue to share updates as we pursue recovery options.
Thank you for your support!