Dodo was hacked for $2 million using a combination of fake token attack and a missing check on contract initialize. This attack affected only V2 pools namely: WSZO, WCRES, ETHA, and FUSI pool.
The source of the problem is that these lines were missing in the init function that would prevent the function to be called multiple times. Attacker exploited the missing check to bypass the flashLoan function balance check and drain the pool.
- Exploiter creates a counterfeit token and initialize the smart contract with it by calling the init function.
- Exploiter calls the sync function which sets the reserve variable, that represents the token balance, to 0.
- Exploiter calls init again to re-initialize - this time with a real token (i.e. tokens in DODO’s pools)
- Exploiter uses a flash loan to transfer all real tokens from the pools and bypass the flash loan check
The reason that flash loan check failed to perform its intended task was because the reserve balances were set to 0 even though the pool had a large amount of the reserve token. And the pool code wrongly assumed it wasn't loosing any tokens.
This is the transaction that caused tha havoc.
- obviously adding the init check to prevent multiple pool initialisation
- some defensive programming where sync would be called inside the init function
OUSD is not vulnerable to this sort of attack because of the initializer modifier that prevent initialize being called multiple times