Flash loan attacks remain one of the most devastating and frequently exploited vulnerability classes in decentralized finance. On September 26, 2024, OnyxDAO lost $3.8 million to a precision-based flash loan exploit targeting forked Compound V2 code—the same protocol that had already been attacked using the same vector less than a year earlier. This tutorial walks through how flash loan exploits work at the contract level, how to detect vulnerable patterns in your own code, and how to implement defenses that actually work.
The Objective
This guide targets experienced Solidity developers and security researchers who want to understand flash loan attack mechanics at a granular level. By the end, you will be able to identify precision loss vulnerabilities in lending protocols, implement protective measures in your smart contracts, and set up monitoring systems that catch exploitation attempts before they complete. The techniques covered apply to any DeFi protocol that handles token exchange rates, lending pools, or price calculations.
Prerequisites
Before proceeding, you should have a solid understanding of Solidity development, including uint256 arithmetic, fixed-point math, and the EVM’s handling of integer division. Familiarity with Compound V2’s interest-bearing token model is helpful, as many modern exploits target code derived from this architecture. You will need access to a development environment with Foundry or Hardhat installed, and ideally some experience reading post-mortem reports from previous flash loan attacks.
Understanding the current threat landscape is essential context. According to Immunefi’s Q3 2024 report published September 26, the crypto industry lost $413 million to hacks and scams in the third quarter alone, with hacker attacks accounting for 99.25 percent of all losses. Flash loan exploits represent a significant portion of DeFi-specific attacks, second only to private key compromises in overall impact.
Step-by-Step Walkthrough
Step 1: Understand the Attack Vector. Flash loans allow users to borrow any amount of tokens without collateral, provided the loan is repaid within the same transaction. This capability enables attackers to manipulate market states—prices, exchange rates, liquidity ratios—at enormous scale without any upfront capital. The OnyxDAO attack exploited a precision loss vulnerability in the exchange rate calculation between an underlying token and its interest-bearing representation.
In Compound V2-derived systems, the exchange rate is calculated as totalCash plus totalBorrows divided by totalSupply of interest-bearing tokens. When a market has very low liquidity, this ratio becomes extremely sensitive to small deposits. The attacker deposited a minimal amount, then used a flash loan to manipulate the numerator of the exchange rate calculation, causing the protocol to believe their small deposit was worth far more than it actually was.
Step 2: Identify Vulnerable Code Patterns. Examine any lending or staking contract that calculates exchange rates, share prices, or reward distributions using integer division. The vulnerable pattern looks like this: a calculation where the denominator (typically totalSupply) is very small relative to the numerator (typically totalAssets), creating a situation where rounding errors become exploitable. Pay special attention to markets that can reach near-zero liquidity, as these are the primary targets.
Look for the following red flags in code reviews: exchange rate calculations that lack minimum bounds checks, markets that allow deposits when totalSupply is below a safe threshold, and any use of raw division without rounding safeguards. The Compound V2 pattern of calculating exchangeRate as (totalCash + totalBorrows + totalReserves) / totalSupply is the canonical example of a vulnerable calculation when totalSupply approaches zero.
Step 3: Implement Precision Safeguards. The most effective defense is enforcing minimum liquidity thresholds before allowing exchange rate calculations to proceed. When totalSupply drops below a critical threshold, the contract should prevent deposits, force a market pause, or switch to a safe default exchange rate. Additionally, use higher-precision math libraries—the OpenZeppelin Math library or Solmate’s FixedPointMathLib provide safer arithmetic operations that reduce rounding errors.
Implement reentrancy guards on all functions that modify exchange rate state, even if the function is not traditionally considered at risk for reentrancy. The OnyxDAO exploit did not require reentrancy, but many flash loan attacks chain multiple vectors together. A comprehensive guard strategy eliminates entire categories of secondary exploits.
Step 4: Add Oracle-Based Validation. Compare your internal exchange rate calculations against external price feeds. If the calculated rate deviates from the oracle rate by more than a reasonable threshold—typically 5 to 10 percent—the contract should pause operations and require manual review. Chainlink price feeds provide reliable oracle data for most major tokens, and custom oracles can be built for exotic assets.
Step 5: Deploy Transaction-Level Monitoring. Set up Forta detection bots or equivalent monitoring that watches for transactions exhibiting flash loan attack characteristics: large borrows followed by rapid state changes in a single transaction, interactions with empty or low-liquidity markets, and exchange rate movements that exceed historical volatility bounds. These monitors cannot prevent attacks in real-time within a single transaction, but they can trigger circuit breakers that halt protocol operations before subsequent transactions execute.
Troubleshooting
If your protocol has already deployed vulnerable code, the immediate priority is assessing whether any markets have low enough liquidity to be exploitable. If they do, pause those markets immediately and communicate transparently with your users. Do not attempt to patch the vulnerability with a hotfix while the market is live—deploy the fix to a testnet first, audit it, and then execute a controlled migration.
If you are forking existing code like Compound V2, do not assume the original code is safe. Many widely-used codebases contain latent vulnerabilities that are only exploitable under specific conditions. Commission a full audit from a reputable security firm that specifically examines the interaction between your forked code and any modifications you have made.
For protocols that have already been exploited, document the attack thoroughly and share the post-mortem with the community. Transparency builds trust and helps other projects avoid the same mistakes. OnyxDAO’s repeated exploitation of the same vulnerability demonstrates the cost of failing to address known issues.
Mastering the Skill
Becoming proficient at flash loan security requires ongoing practice and study. Review past exploits systematically—understand not just what happened, but why the code allowed it and what patterns could have prevented it. Participate in audit contests on platforms like Code4rena and Sherlock, where you will encounter real-world contracts with real vulnerabilities. Build and test your own DeFi protocols with adversarial thinking, assuming that every calculation will be probed by attackers with unlimited capital through flash loans.
The $3.8 million OnyxDAO exploit and the $413 million in Q3 losses documented by Immunefi underscore the stakes. Smart contract security is not optional—it is the difference between a protocol that serves its users and one that drains their funds. As the crypto market continues to grow, with Bitcoin at $65,181 and total market cap exceeding $2.3 trillion, the incentives for attackers will only increase. Build accordingly.
Disclaimer: This article is for educational purposes only and does not constitute professional security advice. Always engage qualified security auditors before deploying smart contracts that handle user funds.

precision loss in empty markets should be lesson one in any DeFi security course. the fact that OnyxDAO hit the same bug twice is wild
same compound v2 fork, same precision bug, twice in one year. at some point its not a bug, its negligence. teams forking without understanding the edge cases
same fork, same precision bug, twice in one year. at some point the team has to own it instead of blaming the attacker
the uint256 rounding section is solid. most devs dont realize exchange rate calculations break at extremely low liquidity levels
^ this. the fix is literally a minimum liquidity check before allowing deposits. 10 lines of code would have saved $3.8M
the minimum liquidity check is literally in the compound v2 source code but commented out with a todo. copypasta devs just skipped it
uint256 rounding is one of those things every dev studies in theory but nobody tests in practice until $3.8M disappears
Good technical writeup but the real issue is teams forking code they dont understand. If you cant audit Compound V2 yourself, dont build on it