Euler added a donation feature in eIP-14: donateToReserves lets you give your own eToken balance to the protocol's reserves. Every other function that reduces a user's collateral ends with a solvency check. This one did not. So the attacker built layered leverage, then deliberately donated his own collateral away to make himself insolvent, and immediately self-liquidated — collecting Euler's own liquidation discount (up to 20%) on a debt he had manufactured. The feature had been live for eight months and sat outside the scope of the protocol's primary auditor.
function donateToReserves(uint subAccountId, uint amount) external nonReentrant { address account = getSubAccount(msg.sender, subAccountId); ... decreaseBalance(assetStorage, assetCache, proxyAddr, account, amountInternal); increaseReserves(assetStorage, assetCache, amountInternal); ... // ❌ every other balance-reducing path ends with: // checkLiquidity(account); // this one returns without it. } // The three-step attack, all inside one transaction: 1. flash-loan & loop deposits → heavily leveraged position 2. donateToReserves(...) → collateral drops, debt untouched, no check 3. liquidate(self) → take the position at up to 20% discount → result: $197M across six Euler markets
Entries in the SAFE database that describe this failure. These share its failure class.
Every figure on this page comes from the post-mortems above, not from us. Losses are US dollars at the time of the incident.
Input validation is one of the 203 classes the SaferICO scanner checks for. It will not review your signing process — but it will read your Solidity.