Auditing DeFi

DeFi protocols are where smart-contract security has its largest dollar stakes. Lending, perpetuals, AMMs, bridges, stablecoins, LSTs, and aggregators collectively secure tens of billions of dollars of user assets, and the bug catalogue across these categories runs to thousands of distinct findings. An auditor who works DeFi must understand the categories well enough to read a new protocol's code and immediately recognize "this is a Uniswap V3 fork with a custom oracle" or "this is a Compound-style market with Aave-style liquidations and an Aave V3 efficiency-mode bug pattern."

This chapter is a domain-by-domain tour: for each major DeFi primitive, what it does mechanically, what the canonical implementations look like, and what audit findings recur. It is not exhaustive — every protocol in scope has its own quirks — but it covers the patterns that appear over and over.

The Common DeFi Threat Model

Before the sub-sections: a small set of failure modes recur across nearly every DeFi category.

1. Price Manipulation

The protocol observes a price (spot, TWAP, oracle, internal exchange rate) and acts on it. The attacker manipulates the price in the same block.

Variants:

  • AMM spot manipulation: a flash-loan-funded large swap moves a pool's price; the protocol reads it; the attacker arbs back.
  • Oracle staleness: the on-chain oracle hasn't updated; the attacker exploits the difference between the stored price and the true market price.
  • TWAP manipulation: the window is too short for the protocol's value at risk; the attacker pays the cost to hold the price off-equilibrium for the window.
  • Cross-pool divergence: two pools for the "same" asset diverge; the protocol uses the wrong one.

Mitigations: pull oracles with attestation, TWAP windows sized to manipulation cost, multi-source oracle aggregation, sanity-bound checks.

2. Re-entrancy

A user-callable function makes an external call before completing its state update; the called contract re-enters and observes inconsistent state.

Modern Solidity tooling and the CEI pattern handle the classical reentrancy bug. The current findings tend to be:

  • Cross-function reentrancy: function A calls out; function B (different function in the same contract) is re-entered; B reads state A hasn't yet updated.
  • Read-only reentrancy: an external contract reads the victim's state during the callback; the read returns inconsistent values (Curve's 2023 read-only re-entrancy in Vyper was the canonical example).
  • Reentrancy via ERC-777 / ERC-1155 hooks: "token transfer" can be a callback to the recipient.
  • Reentrancy via callback patterns: flash-loan callbacks, swap callbacks, UniV4 hooks.

Audit posture: trace every external call's reachable code; ask "if this called arbitrary code, what could that code see and do?"

3. Rounding and Inflation Attacks

Integer math in finite-precision arithmetic always has rounding errors. The question is whether those errors can be turned into a profit.

The canonical pattern is the ERC-4626 "donation / inflation" attack:

  1. Vault starts empty.
  2. Attacker deposits 1 wei, receiving 1 share.
  3. Attacker donates 1e18 tokens directly to the vault (no shares issued).
  4. Victim deposits 2e18 tokens — but at the new exchange rate, this is worth ~2 shares ÷ floor → 1 share.
  5. Total shares: 2. Total assets: 3e18. Victim withdraws 1.5e18 (loses 0.5e18 to attacker).

Mitigations:

  • Initial seed deposit to the vault by the deployer.
  • Virtual shares / virtual offset (OpenZeppelin v4.9+, ERC-4626 default behavior).
  • Minimum deposit / share amount.

4. Authorization Confusion

The protocol allows action X under condition Y, but Y can be satisfied via an unintended path.

Examples:

  • A "self-liquidation" path that has different invariants than third-party liquidation.
  • A "claim on behalf of" path that doesn't verify the caller is authorized.
  • A delegate-call path that lets the caller execute arbitrary code in the protocol's context.

This is the broadest category; the audit posture is to enumerate every state-changing function and ask, for each one, "who can call this and under what circumstances?"

5. Composability Breakage

DeFi protocols are designed to be combined. Bugs frequently emerge at the boundary: when protocol A calls protocol B, and B does something A's author didn't expect.

Examples:

  • Calling an AMM swap inside a CEI-violating function, where the swap callback re-enters.
  • Trusting a price returned by another protocol whose own oracle is manipulable.
  • Composing two protocols whose individual invariants are correct but whose combined behavior is not.

Composability is unavoidable in DeFi audits. The mitigation is to know what assumptions every called protocol makes about its callers, and verify the auditing protocol respects them all.

What to Expect in This Chapter

The sub-sections that follow cover, in turn:

Each section walks the canonical implementations, the recurring findings, and the questions an auditor should bring to a new instance of the category.

A general practitioner doesn't need to be an expert in every one of these. They do need to recognize which category a protocol falls into, and know when to either go deep themselves or pull in a specialist.